mirror of
https://github.com/oven-sh/bun
synced 2026-02-06 17:08:51 +00:00
Compare commits
7 Commits
patch-1
...
kai/mimall
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60d565d267 | ||
|
|
55ca88b9b7 | ||
|
|
54ad155668 | ||
|
|
709d9f858a | ||
|
|
ea690d81d1 | ||
|
|
3e9842e1e1 | ||
|
|
cf0bdce7d4 |
@@ -371,7 +371,7 @@ function getZigAgent(platform, options) {
|
||||
* @returns {Agent}
|
||||
*/
|
||||
function getTestAgent(platform, options) {
|
||||
const { os, arch, profile } = platform;
|
||||
const { os, arch } = platform;
|
||||
|
||||
if (os === "darwin") {
|
||||
return {
|
||||
@@ -391,13 +391,6 @@ function getTestAgent(platform, options) {
|
||||
}
|
||||
|
||||
if (arch === "aarch64") {
|
||||
if (profile === "asan") {
|
||||
return getEc2Agent(platform, options, {
|
||||
instanceType: "c8g.2xlarge",
|
||||
cpuCount: 2,
|
||||
threadsPerCore: 1,
|
||||
});
|
||||
}
|
||||
return getEc2Agent(platform, options, {
|
||||
instanceType: "c8g.xlarge",
|
||||
cpuCount: 2,
|
||||
@@ -405,13 +398,6 @@ function getTestAgent(platform, options) {
|
||||
});
|
||||
}
|
||||
|
||||
if (profile === "asan") {
|
||||
return getEc2Agent(platform, options, {
|
||||
instanceType: "c7i.2xlarge",
|
||||
cpuCount: 2,
|
||||
threadsPerCore: 1,
|
||||
});
|
||||
}
|
||||
return getEc2Agent(platform, options, {
|
||||
instanceType: "c7i.xlarge",
|
||||
cpuCount: 2,
|
||||
@@ -448,17 +434,11 @@ function getBuildEnv(target, options) {
|
||||
* @param {PipelineOptions} options
|
||||
* @returns {string}
|
||||
*/
|
||||
function getBuildCommand(target, options, label) {
|
||||
function getBuildCommand(target, options) {
|
||||
const { profile } = target;
|
||||
const buildProfile = profile || "release";
|
||||
|
||||
if (target.os === "windows" && label === "build-bun") {
|
||||
// Only sign release builds, not canary builds (DigiCert charges per signature)
|
||||
const enableSigning = !options.canary ? " -DENABLE_WINDOWS_CODESIGNING=ON" : "";
|
||||
return `bun run build:${buildProfile}${enableSigning}`;
|
||||
}
|
||||
|
||||
return `bun run build:${buildProfile}`;
|
||||
const label = profile || "release";
|
||||
return `bun run build:${label}`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -552,10 +532,9 @@ function getLinkBunStep(platform, options) {
|
||||
cancel_on_build_failing: isMergeQueue(),
|
||||
env: {
|
||||
BUN_LINK_ONLY: "ON",
|
||||
ASAN_OPTIONS: "allow_user_segv_handler=1:disable_coredump=0:detect_leaks=0",
|
||||
...getBuildEnv(platform, options),
|
||||
},
|
||||
command: `${getBuildCommand(platform, options, "build-bun")} --target bun`,
|
||||
command: `${getBuildCommand(platform, options)} --target bun`,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -616,9 +595,6 @@ function getTestBunStep(platform, options, testOptions = {}) {
|
||||
cancel_on_build_failing: isMergeQueue(),
|
||||
parallelism: unifiedTests ? undefined : os === "darwin" ? 2 : 10,
|
||||
timeout_in_minutes: profile === "asan" || os === "windows" ? 45 : 30,
|
||||
env: {
|
||||
ASAN_OPTIONS: "allow_user_segv_handler=1:disable_coredump=0:detect_leaks=0",
|
||||
},
|
||||
command:
|
||||
os === "windows"
|
||||
? `node .\\scripts\\runner.node.mjs ${args.join(" ")}`
|
||||
|
||||
@@ -1,464 +0,0 @@
|
||||
# Windows Code Signing Script for Bun
|
||||
# Uses DigiCert KeyLocker for Authenticode signing
|
||||
# Native PowerShell implementation - no path translation issues
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$BunProfileExe,
|
||||
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$BunExe
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$ProgressPreference = "SilentlyContinue"
|
||||
|
||||
# Logging functions
|
||||
function Log-Info {
|
||||
param([string]$Message)
|
||||
Write-Host "[INFO] $Message" -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
function Log-Success {
|
||||
param([string]$Message)
|
||||
Write-Host "[SUCCESS] $Message" -ForegroundColor Green
|
||||
}
|
||||
|
||||
function Log-Error {
|
||||
param([string]$Message)
|
||||
Write-Host "[ERROR] $Message" -ForegroundColor Red
|
||||
}
|
||||
|
||||
function Log-Debug {
|
||||
param([string]$Message)
|
||||
if ($env:DEBUG -eq "true" -or $env:DEBUG -eq "1") {
|
||||
Write-Host "[DEBUG] $Message" -ForegroundColor Gray
|
||||
}
|
||||
}
|
||||
|
||||
# Load Visual Studio environment if not already loaded
|
||||
function Ensure-VSEnvironment {
|
||||
if ($null -eq $env:VSINSTALLDIR) {
|
||||
Log-Info "Loading Visual Studio environment..."
|
||||
|
||||
$vswhere = "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"
|
||||
if (!(Test-Path $vswhere)) {
|
||||
throw "Command not found: vswhere (did you install Visual Studio?)"
|
||||
}
|
||||
|
||||
$vsDir = & $vswhere -prerelease -latest -property installationPath
|
||||
if ($null -eq $vsDir) {
|
||||
$vsDir = Get-ChildItem -Path "C:\Program Files\Microsoft Visual Studio\2022" -Directory -ErrorAction SilentlyContinue
|
||||
if ($null -eq $vsDir) {
|
||||
throw "Visual Studio directory not found."
|
||||
}
|
||||
$vsDir = $vsDir.FullName
|
||||
}
|
||||
|
||||
Push-Location $vsDir
|
||||
try {
|
||||
$vsShell = Join-Path -Path $vsDir -ChildPath "Common7\Tools\Launch-VsDevShell.ps1"
|
||||
. $vsShell -Arch amd64 -HostArch amd64
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
Log-Success "Visual Studio environment loaded"
|
||||
}
|
||||
|
||||
if ($env:VSCMD_ARG_TGT_ARCH -eq "x86") {
|
||||
throw "Visual Studio environment is targeting 32 bit, but only 64 bit is supported."
|
||||
}
|
||||
}
|
||||
|
||||
# Check for required environment variables
|
||||
function Check-Environment {
|
||||
Log-Info "Checking environment variables..."
|
||||
|
||||
$required = @{
|
||||
"SM_API_KEY" = $env:SM_API_KEY
|
||||
"SM_CLIENT_CERT_PASSWORD" = $env:SM_CLIENT_CERT_PASSWORD
|
||||
"SM_KEYPAIR_ALIAS" = $env:SM_KEYPAIR_ALIAS
|
||||
"SM_HOST" = $env:SM_HOST
|
||||
"SM_CLIENT_CERT_FILE" = $env:SM_CLIENT_CERT_FILE
|
||||
}
|
||||
|
||||
$missing = @()
|
||||
foreach ($key in $required.Keys) {
|
||||
if ([string]::IsNullOrEmpty($required[$key])) {
|
||||
$missing += $key
|
||||
} else {
|
||||
Log-Debug "$key is set (length: $($required[$key].Length))"
|
||||
}
|
||||
}
|
||||
|
||||
if ($missing.Count -gt 0) {
|
||||
throw "Missing required environment variables: $($missing -join ', ')"
|
||||
}
|
||||
|
||||
Log-Success "All required environment variables are present"
|
||||
}
|
||||
|
||||
# Setup certificate file
|
||||
function Setup-Certificate {
|
||||
Log-Info "Setting up certificate..."
|
||||
|
||||
# Always try to decode as base64 first
|
||||
# If it fails, then treat as file path
|
||||
try {
|
||||
Log-Info "Attempting to decode certificate as base64..."
|
||||
Log-Debug "Input string length: $($env:SM_CLIENT_CERT_FILE.Length) characters"
|
||||
|
||||
$tempCertPath = Join-Path $env:TEMP "digicert_cert_$(Get-Random).p12"
|
||||
|
||||
# Try to decode as base64
|
||||
$certBytes = [System.Convert]::FromBase64String($env:SM_CLIENT_CERT_FILE)
|
||||
[System.IO.File]::WriteAllBytes($tempCertPath, $certBytes)
|
||||
|
||||
# Validate the decoded certificate size
|
||||
$fileSize = (Get-Item $tempCertPath).Length
|
||||
if ($fileSize -lt 100) {
|
||||
throw "Decoded certificate too small: $fileSize bytes (expected >100 bytes)"
|
||||
}
|
||||
|
||||
# Update environment to point to file
|
||||
$env:SM_CLIENT_CERT_FILE = $tempCertPath
|
||||
|
||||
Log-Success "Certificate decoded and written to: $tempCertPath"
|
||||
Log-Debug "Decoded certificate file size: $fileSize bytes"
|
||||
|
||||
# Register cleanup
|
||||
$global:TEMP_CERT_PATH = $tempCertPath
|
||||
|
||||
} catch {
|
||||
# If base64 decode fails, check if it's a file path
|
||||
Log-Info "Base64 decode failed, checking if it's a file path..."
|
||||
Log-Debug "Decode error: $_"
|
||||
|
||||
if (Test-Path $env:SM_CLIENT_CERT_FILE) {
|
||||
$fileSize = (Get-Item $env:SM_CLIENT_CERT_FILE).Length
|
||||
|
||||
# Validate file size
|
||||
if ($fileSize -lt 100) {
|
||||
throw "Certificate file too small: $fileSize bytes at $env:SM_CLIENT_CERT_FILE (possibly corrupted)"
|
||||
}
|
||||
|
||||
Log-Info "Using certificate file: $env:SM_CLIENT_CERT_FILE"
|
||||
Log-Debug "Certificate file size: $fileSize bytes"
|
||||
} else {
|
||||
throw "SM_CLIENT_CERT_FILE is neither valid base64 nor an existing file: $env:SM_CLIENT_CERT_FILE"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Install DigiCert KeyLocker tools
|
||||
function Install-KeyLocker {
|
||||
Log-Info "Setting up DigiCert KeyLocker tools..."
|
||||
|
||||
# Define our controlled installation directory
|
||||
$installDir = "C:\BuildTools\DigiCert"
|
||||
$smctlPath = Join-Path $installDir "smctl.exe"
|
||||
|
||||
# Check if already installed in our controlled location
|
||||
if (Test-Path $smctlPath) {
|
||||
Log-Success "KeyLocker tools already installed at: $smctlPath"
|
||||
|
||||
# Add to PATH if not already there
|
||||
if ($env:PATH -notlike "*$installDir*") {
|
||||
$env:PATH = "$installDir;$env:PATH"
|
||||
Log-Info "Added to PATH: $installDir"
|
||||
}
|
||||
|
||||
return $smctlPath
|
||||
}
|
||||
|
||||
Log-Info "Installing KeyLocker tools to: $installDir"
|
||||
|
||||
# Create the installation directory if it doesn't exist
|
||||
if (!(Test-Path $installDir)) {
|
||||
Log-Info "Creating installation directory: $installDir"
|
||||
try {
|
||||
New-Item -ItemType Directory -Path $installDir -Force | Out-Null
|
||||
Log-Success "Created directory: $installDir"
|
||||
} catch {
|
||||
throw "Failed to create directory $installDir : $_"
|
||||
}
|
||||
}
|
||||
|
||||
# Download MSI installer
|
||||
$msiUrl = "https://bun-ci-assets.bun.sh/Keylockertools-windows-x64.msi"
|
||||
$msiPath = Join-Path $env:TEMP "Keylockertools-windows-x64.msi"
|
||||
|
||||
Log-Info "Downloading MSI from: $msiUrl"
|
||||
Log-Info "Downloading to: $msiPath"
|
||||
|
||||
try {
|
||||
# Remove existing MSI if present
|
||||
if (Test-Path $msiPath) {
|
||||
Remove-Item $msiPath -Force
|
||||
Log-Debug "Removed existing MSI file"
|
||||
}
|
||||
|
||||
# Download with progress tracking
|
||||
$webClient = New-Object System.Net.WebClient
|
||||
$webClient.DownloadFile($msiUrl, $msiPath)
|
||||
|
||||
if (!(Test-Path $msiPath)) {
|
||||
throw "MSI download failed - file not found"
|
||||
}
|
||||
|
||||
$fileSize = (Get-Item $msiPath).Length
|
||||
Log-Success "MSI downloaded successfully (size: $fileSize bytes)"
|
||||
|
||||
} catch {
|
||||
throw "Failed to download MSI: $_"
|
||||
}
|
||||
|
||||
# Install MSI
|
||||
Log-Info "Installing MSI..."
|
||||
Log-Debug "MSI path: $msiPath"
|
||||
Log-Debug "File exists: $(Test-Path $msiPath)"
|
||||
Log-Debug "File size: $((Get-Item $msiPath).Length) bytes"
|
||||
|
||||
# Check if running as administrator
|
||||
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
Log-Info "Running as administrator: $isAdmin"
|
||||
|
||||
# Install MSI silently to our controlled directory
|
||||
$arguments = @(
|
||||
"/i", "`"$msiPath`"",
|
||||
"/quiet",
|
||||
"/norestart",
|
||||
"TARGETDIR=`"$installDir`"",
|
||||
"INSTALLDIR=`"$installDir`"",
|
||||
"ACCEPT_EULA=1",
|
||||
"ADDLOCAL=ALL"
|
||||
)
|
||||
|
||||
Log-Debug "Running: msiexec.exe $($arguments -join ' ')"
|
||||
Log-Info "Installing to: $installDir"
|
||||
|
||||
$process = Start-Process -FilePath "msiexec.exe" -ArgumentList $arguments -Wait -PassThru -NoNewWindow
|
||||
|
||||
if ($process.ExitCode -ne 0) {
|
||||
Log-Error "MSI installation failed with exit code: $($process.ExitCode)"
|
||||
|
||||
# Try to get error details from event log
|
||||
try {
|
||||
$events = Get-WinEvent -LogName "Application" -MaxEvents 10 |
|
||||
Where-Object { $_.ProviderName -eq "MsiInstaller" -and $_.TimeCreated -gt (Get-Date).AddMinutes(-1) }
|
||||
|
||||
foreach ($event in $events) {
|
||||
Log-Debug "MSI Event: $($event.Message)"
|
||||
}
|
||||
} catch {
|
||||
Log-Debug "Could not retrieve MSI installation events"
|
||||
}
|
||||
|
||||
throw "MSI installation failed with exit code: $($process.ExitCode)"
|
||||
}
|
||||
|
||||
Log-Success "MSI installation completed"
|
||||
|
||||
# Wait for installation to complete
|
||||
Start-Sleep -Seconds 2
|
||||
|
||||
# Verify smctl.exe exists in our controlled location
|
||||
if (Test-Path $smctlPath) {
|
||||
Log-Success "KeyLocker tools installed successfully at: $smctlPath"
|
||||
|
||||
# Add to PATH
|
||||
$env:PATH = "$installDir;$env:PATH"
|
||||
Log-Info "Added to PATH: $installDir"
|
||||
|
||||
return $smctlPath
|
||||
}
|
||||
|
||||
# If not in our expected location, check if it installed somewhere in the directory
|
||||
$found = Get-ChildItem -Path $installDir -Filter "smctl.exe" -Recurse -ErrorAction SilentlyContinue |
|
||||
Select-Object -First 1
|
||||
|
||||
if ($found) {
|
||||
Log-Success "Found smctl.exe at: $($found.FullName)"
|
||||
$smctlDir = $found.DirectoryName
|
||||
$env:PATH = "$smctlDir;$env:PATH"
|
||||
return $found.FullName
|
||||
}
|
||||
|
||||
throw "KeyLocker tools installation succeeded but smctl.exe not found in $installDir"
|
||||
}
|
||||
|
||||
# Configure KeyLocker
|
||||
function Configure-KeyLocker {
|
||||
param([string]$SmctlPath)
|
||||
|
||||
Log-Info "Configuring KeyLocker..."
|
||||
|
||||
# Verify smctl is accessible
|
||||
try {
|
||||
$version = & $SmctlPath --version 2>&1
|
||||
Log-Debug "smctl version: $version"
|
||||
} catch {
|
||||
throw "Failed to run smctl: $_"
|
||||
}
|
||||
|
||||
# Configure KeyLocker credentials and environment
|
||||
Log-Info "Configuring KeyLocker credentials..."
|
||||
|
||||
try {
|
||||
# Save credentials (API key and password)
|
||||
Log-Info "Saving credentials to OS store..."
|
||||
$saveOutput = & $SmctlPath credentials save $env:SM_API_KEY $env:SM_CLIENT_CERT_PASSWORD 2>&1 | Out-String
|
||||
Log-Debug "Credentials save output: $saveOutput"
|
||||
|
||||
if ($saveOutput -like "*Credentials saved*") {
|
||||
Log-Success "Credentials saved successfully"
|
||||
}
|
||||
|
||||
# Set environment variables for smctl
|
||||
Log-Info "Setting KeyLocker environment variables..."
|
||||
$env:SM_HOST = $env:SM_HOST # Already set, but ensure it's available
|
||||
$env:SM_API_KEY = $env:SM_API_KEY # Already set
|
||||
$env:SM_CLIENT_CERT_FILE = $env:SM_CLIENT_CERT_FILE # Path to decoded cert file
|
||||
Log-Debug "SM_HOST: $env:SM_HOST"
|
||||
Log-Debug "SM_CLIENT_CERT_FILE: $env:SM_CLIENT_CERT_FILE"
|
||||
|
||||
# Run health check
|
||||
Log-Info "Running KeyLocker health check..."
|
||||
$healthOutput = & $SmctlPath healthcheck 2>&1 | Out-String
|
||||
Log-Debug "Health check output: $healthOutput"
|
||||
|
||||
if ($healthOutput -like "*Healthy*" -or $healthOutput -like "*SUCCESS*" -or $LASTEXITCODE -eq 0) {
|
||||
Log-Success "KeyLocker health check passed"
|
||||
} else {
|
||||
Log-Error "Health check failed: $healthOutput"
|
||||
# Don't throw here, sometimes healthcheck is flaky but signing still works
|
||||
}
|
||||
|
||||
# Sync certificates to Windows certificate store
|
||||
Log-Info "Syncing certificates to Windows store..."
|
||||
$syncOutput = & $SmctlPath windows certsync 2>&1 | Out-String
|
||||
Log-Debug "Certificate sync output: $syncOutput"
|
||||
|
||||
if ($syncOutput -like "*success*" -or $syncOutput -like "*synced*" -or $LASTEXITCODE -eq 0) {
|
||||
Log-Success "Certificates synced to Windows store"
|
||||
} else {
|
||||
Log-Info "Certificate sync output: $syncOutput"
|
||||
}
|
||||
|
||||
} catch {
|
||||
throw "Failed to configure KeyLocker: $_"
|
||||
}
|
||||
}
|
||||
|
||||
# Sign an executable
|
||||
function Sign-Executable {
|
||||
param(
|
||||
[string]$ExePath,
|
||||
[string]$SmctlPath
|
||||
)
|
||||
|
||||
if (!(Test-Path $ExePath)) {
|
||||
throw "Executable not found: $ExePath"
|
||||
}
|
||||
|
||||
$fileName = Split-Path $ExePath -Leaf
|
||||
Log-Info "Signing $fileName..."
|
||||
Log-Debug "Full path: $ExePath"
|
||||
Log-Debug "File size: $((Get-Item $ExePath).Length) bytes"
|
||||
|
||||
# Check if already signed
|
||||
$existingSig = Get-AuthenticodeSignature $ExePath
|
||||
if ($existingSig.Status -eq "Valid") {
|
||||
Log-Info "$fileName is already signed by: $($existingSig.SignerCertificate.Subject)"
|
||||
Log-Info "Skipping re-signing"
|
||||
return
|
||||
}
|
||||
|
||||
# Sign the executable using smctl
|
||||
try {
|
||||
# smctl sign command with keypair-alias
|
||||
$signArgs = @(
|
||||
"sign",
|
||||
"--keypair-alias", $env:SM_KEYPAIR_ALIAS,
|
||||
"--input", $ExePath,
|
||||
"--verbose"
|
||||
)
|
||||
|
||||
Log-Debug "Running: $SmctlPath $($signArgs -join ' ')"
|
||||
|
||||
$signOutput = & $SmctlPath $signArgs 2>&1 | Out-String
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Log-Error "Signing output: $signOutput"
|
||||
throw "Signing failed with exit code: $LASTEXITCODE"
|
||||
}
|
||||
|
||||
Log-Debug "Signing output: $signOutput"
|
||||
Log-Success "Signing command completed"
|
||||
|
||||
} catch {
|
||||
throw "Failed to sign $fileName : $_"
|
||||
}
|
||||
|
||||
# Verify signature
|
||||
$newSig = Get-AuthenticodeSignature $ExePath
|
||||
|
||||
if ($newSig.Status -eq "Valid") {
|
||||
Log-Success "$fileName signed successfully"
|
||||
Log-Info "Signed by: $($newSig.SignerCertificate.Subject)"
|
||||
Log-Info "Thumbprint: $($newSig.SignerCertificate.Thumbprint)"
|
||||
Log-Info "Valid from: $($newSig.SignerCertificate.NotBefore) to $($newSig.SignerCertificate.NotAfter)"
|
||||
} else {
|
||||
throw "$fileName signature verification failed: $($newSig.Status) - $($newSig.StatusMessage)"
|
||||
}
|
||||
}
|
||||
|
||||
# Cleanup function
|
||||
function Cleanup {
|
||||
if ($global:TEMP_CERT_PATH -and (Test-Path $global:TEMP_CERT_PATH)) {
|
||||
try {
|
||||
Remove-Item $global:TEMP_CERT_PATH -Force
|
||||
Log-Info "Cleaned up temporary certificate"
|
||||
} catch {
|
||||
Log-Error "Failed to cleanup temporary certificate: $_"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Main execution
|
||||
try {
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host " Windows Code Signing for Bun" -ForegroundColor Cyan
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
|
||||
# Ensure we're in a VS environment
|
||||
Ensure-VSEnvironment
|
||||
|
||||
# Check environment variables
|
||||
Check-Environment
|
||||
|
||||
# Setup certificate
|
||||
Setup-Certificate
|
||||
|
||||
# Install and configure KeyLocker
|
||||
$smctlPath = Install-KeyLocker
|
||||
Configure-KeyLocker -SmctlPath $smctlPath
|
||||
|
||||
# Sign both executables
|
||||
Sign-Executable -ExePath $BunProfileExe -SmctlPath $smctlPath
|
||||
Sign-Executable -ExePath $BunExe -SmctlPath $smctlPath
|
||||
|
||||
Write-Host "========================================" -ForegroundColor Green
|
||||
Write-Host " Code signing completed successfully!" -ForegroundColor Green
|
||||
Write-Host "========================================" -ForegroundColor Green
|
||||
|
||||
exit 0
|
||||
|
||||
} catch {
|
||||
Log-Error "Code signing failed: $_"
|
||||
exit 1
|
||||
|
||||
} finally {
|
||||
Cleanup
|
||||
}
|
||||
4
.github/CODEOWNERS
vendored
4
.github/CODEOWNERS
vendored
@@ -3,7 +3,3 @@
|
||||
|
||||
# Tests
|
||||
/test/expectations.txt @Jarred-Sumner
|
||||
|
||||
# Types
|
||||
*.d.ts @alii
|
||||
/packages/bun-types/ @alii
|
||||
|
||||
2
.github/actions/bump/action.yml
vendored
2
.github/actions/bump/action.yml
vendored
@@ -25,7 +25,7 @@ runs:
|
||||
echo "version=$LATEST" >> $GITHUB_OUTPUT
|
||||
echo "message=$MESSAGE" >> $GITHUB_OUTPUT
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
add-paths: |
|
||||
CMakeLists.txt
|
||||
|
||||
19
.github/workflows/auto-assign-types.yml
vendored
19
.github/workflows/auto-assign-types.yml
vendored
@@ -1,19 +0,0 @@
|
||||
name: Auto Assign Types Issues
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [labeled]
|
||||
|
||||
jobs:
|
||||
auto-assign:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.label.name == 'types'
|
||||
permissions:
|
||||
issues: write
|
||||
steps:
|
||||
- name: Assign to alii
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
run: |
|
||||
gh issue edit ${{ github.event.issue.number }} --add-assignee alii
|
||||
4
.github/workflows/auto-label-claude-prs.yml
vendored
4
.github/workflows/auto-label-claude-prs.yml
vendored
@@ -6,7 +6,7 @@ on:
|
||||
|
||||
jobs:
|
||||
auto-label:
|
||||
if: github.event.pull_request.user.login == 'robobun' || contains(github.event.pull_request.body, '🤖 Generated with')
|
||||
if: github.event.pull_request.user.login == 'robobun'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -21,4 +21,4 @@ jobs:
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
labels: ['claude']
|
||||
});
|
||||
});
|
||||
24
.github/workflows/format.yml
vendored
24
.github/workflows/format.yml
vendored
@@ -8,8 +8,10 @@ on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
merge_group:
|
||||
push:
|
||||
branches: ["main"]
|
||||
env:
|
||||
BUN_VERSION: "1.2.20"
|
||||
BUN_VERSION: "1.2.11"
|
||||
LLVM_VERSION: "19.1.7"
|
||||
LLVM_VERSION_MAJOR: "19"
|
||||
|
||||
@@ -35,14 +37,13 @@ jobs:
|
||||
- name: Setup Dependencies
|
||||
run: |
|
||||
bun install
|
||||
bun scripts/glob-sources.mjs
|
||||
- name: Format Code
|
||||
run: |
|
||||
# Start prettier in background with prefixed output
|
||||
echo "::group::Prettier"
|
||||
(bun run prettier 2>&1 | sed 's/^/[prettier] /' || echo "[prettier] Failed with exit code $?") &
|
||||
PRETTIER_PID=$!
|
||||
|
||||
|
||||
# Start clang-format installation and formatting in background with prefixed output
|
||||
echo "::group::Clang-format"
|
||||
(
|
||||
@@ -55,13 +56,13 @@ jobs:
|
||||
LLVM_VERSION_MAJOR=${{ env.LLVM_VERSION_MAJOR }} ./scripts/run-clang-format.sh format 2>&1 | sed 's/^/[clang-format] /'
|
||||
) &
|
||||
CLANG_PID=$!
|
||||
|
||||
|
||||
# Setup Zig in temp directory and run zig fmt in background with prefixed output
|
||||
echo "::group::Zig fmt"
|
||||
(
|
||||
ZIG_TEMP=$(mktemp -d)
|
||||
echo "[zig] Downloading Zig (musl build)..."
|
||||
wget -q -O "$ZIG_TEMP/zig.zip" https://github.com/oven-sh/zig/releases/download/autobuild-e0b7c318f318196c5f81fdf3423816a7b5bb3112/bootstrap-x86_64-linux-musl.zip
|
||||
wget -q -O "$ZIG_TEMP/zig.zip" https://github.com/oven-sh/zig/releases/download/autobuild-d1a4e0b0ddc75f37c6a090b97eef0cbb6335556e/bootstrap-x86_64-linux-musl.zip
|
||||
unzip -q -d "$ZIG_TEMP" "$ZIG_TEMP/zig.zip"
|
||||
export PATH="$ZIG_TEMP/bootstrap-x86_64-linux-musl:$PATH"
|
||||
echo "[zig] Running zig fmt..."
|
||||
@@ -71,39 +72,38 @@ jobs:
|
||||
rm -rf "$ZIG_TEMP"
|
||||
) &
|
||||
ZIG_PID=$!
|
||||
|
||||
|
||||
# Wait for all formatting tasks to complete
|
||||
echo ""
|
||||
echo "Running formatters in parallel..."
|
||||
FAILED=0
|
||||
|
||||
|
||||
if ! wait $PRETTIER_PID; then
|
||||
echo "::error::Prettier failed"
|
||||
FAILED=1
|
||||
fi
|
||||
echo "::endgroup::"
|
||||
|
||||
|
||||
if ! wait $CLANG_PID; then
|
||||
echo "::error::Clang-format failed"
|
||||
FAILED=1
|
||||
fi
|
||||
echo "::endgroup::"
|
||||
|
||||
|
||||
if ! wait $ZIG_PID; then
|
||||
echo "::error::Zig fmt failed"
|
||||
FAILED=1
|
||||
fi
|
||||
echo "::endgroup::"
|
||||
|
||||
|
||||
# Exit with error if any formatter failed
|
||||
if [ $FAILED -eq 1 ]; then
|
||||
echo "::error::One or more formatters failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
echo "✅ All formatters completed successfully"
|
||||
- name: Ban Words
|
||||
run: |
|
||||
bun ./test/internal/ban-words.test.ts
|
||||
git rm -f cmake/sources/*.txt || true
|
||||
- uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27
|
||||
|
||||
41
.github/workflows/glob-sources.yml
vendored
Normal file
41
.github/workflows/glob-sources.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: Glob Sources
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
BUN_VERSION: "1.2.11"
|
||||
|
||||
jobs:
|
||||
glob-sources:
|
||||
name: Glob Sources
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config --global core.autocrlf true
|
||||
git config --global core.ignorecase true
|
||||
git config --global core.precomposeUnicode true
|
||||
- name: Setup Bun
|
||||
uses: ./.github/actions/setup-bun
|
||||
with:
|
||||
bun-version: ${{ env.BUN_VERSION }}
|
||||
- name: Setup Dependencies
|
||||
run: |
|
||||
bun install
|
||||
- name: Glob sources
|
||||
run: bun scripts/glob-sources.mjs
|
||||
- name: Commit
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: "`bun scripts/glob-sources.mjs`"
|
||||
|
||||
104
.github/workflows/labeled.yml
vendored
104
.github/workflows/labeled.yml
vendored
@@ -5,8 +5,6 @@ env:
|
||||
on:
|
||||
issues:
|
||||
types: [labeled]
|
||||
pull_request_target:
|
||||
types: [labeled, opened, reopened, synchronize, unlabeled]
|
||||
|
||||
jobs:
|
||||
# on-bug:
|
||||
@@ -45,46 +43,9 @@ jobs:
|
||||
# token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# issue-number: ${{ github.event.issue.number }}
|
||||
# labels: ${{ steps.add-labels.outputs.labels }}
|
||||
on-slop:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'pull_request_target' && contains(github.event.pull_request.labels.*.name, 'slop')
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
contents: write
|
||||
steps:
|
||||
- name: Update PR title and body for slop and close
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const pr = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: context.issue.number
|
||||
});
|
||||
|
||||
await github.rest.pulls.update({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: context.issue.number,
|
||||
title: 'ai slop',
|
||||
body: 'This PR has been marked as AI slop and the description has been updated to avoid confusion or misleading reviewers.\n\nMany AI PRs are fine, but sometimes they submit a PR too early, fail to test if the problem is real, fail to reproduce the problem, or fail to test that the problem is fixed. If you think this PR is not AI slop, please leave a comment.',
|
||||
state: 'closed'
|
||||
});
|
||||
|
||||
// Delete the branch if it's from a fork or if it's not a protected branch
|
||||
try {
|
||||
await github.rest.git.deleteRef({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: `heads/${pr.data.head.ref}`
|
||||
});
|
||||
} catch (error) {
|
||||
console.log('Could not delete branch:', error.message);
|
||||
}
|
||||
on-labeled:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'issues' && (github.event.label.name == 'crash' || github.event.label.name == 'needs repro')
|
||||
if: github.event.label.name == 'crash' || github.event.label.name == 'needs repro'
|
||||
permissions:
|
||||
issues: write
|
||||
steps:
|
||||
@@ -105,16 +66,11 @@ jobs:
|
||||
env:
|
||||
GITHUB_ISSUE_BODY: ${{ github.event.issue.body }}
|
||||
GITHUB_ISSUE_TITLE: ${{ github.event.issue.title }}
|
||||
GITHUB_ISSUE_NUMBER: ${{ github.event.issue.number }}
|
||||
shell: bash
|
||||
run: |
|
||||
LABELS=$(bun scripts/read-issue.ts)
|
||||
bun scripts/is-outdated.ts
|
||||
|
||||
# Check for patterns that should close the issue
|
||||
CLOSE_ACTION=$(bun scripts/handle-crash-patterns.ts)
|
||||
echo "close-action=$CLOSE_ACTION" >> $GITHUB_OUTPUT
|
||||
|
||||
if [[ -f "is-outdated.txt" ]]; then
|
||||
echo "is-outdated=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
@@ -123,10 +79,6 @@ jobs:
|
||||
echo "outdated=$(cat outdated.txt)" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
if [[ -f "is-standalone.txt" ]]; then
|
||||
echo "is-standalone=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
if [[ -f "is-very-outdated.txt" ]]; then
|
||||
echo "is-very-outdated=true" >> $GITHUB_OUTPUT
|
||||
LABELS="$LABELS,old-version"
|
||||
@@ -136,32 +88,9 @@ jobs:
|
||||
|
||||
echo "latest=$(cat LATEST)" >> $GITHUB_OUTPUT
|
||||
echo "labels=$LABELS" >> $GITHUB_OUTPUT
|
||||
rm -rf is-outdated.txt outdated.txt latest.txt is-very-outdated.txt is-standalone.txt
|
||||
- name: Close issue if pattern detected
|
||||
if: github.event.label.name == 'crash' && fromJson(steps.add-labels.outputs.close-action).close == true
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const closeAction = JSON.parse('${{ steps.add-labels.outputs.close-action }}');
|
||||
|
||||
// Comment with the reason
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
body: closeAction.comment
|
||||
});
|
||||
|
||||
// Close the issue
|
||||
await github.rest.issues.update({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
state: 'closed',
|
||||
state_reason: closeAction.reason
|
||||
});
|
||||
rm -rf is-outdated.txt outdated.txt latest.txt is-very-outdated.txt
|
||||
- name: Generate comment text with Sentry Link
|
||||
if: github.event.label.name == 'crash' && fromJson(steps.add-labels.outputs.close-action).close != true
|
||||
if: github.event.label.name == 'crash'
|
||||
# ignore if fail
|
||||
continue-on-error: true
|
||||
id: generate-comment-text
|
||||
@@ -195,17 +124,8 @@ jobs:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
labels: ${{ steps.add-labels.outputs.labels }}
|
||||
- name: Comment outdated (standalone executable)
|
||||
if: steps.add-labels.outputs.is-outdated == 'true' && steps.add-labels.outputs.is-standalone == 'true' && github.event.label.name == 'crash' && steps.generate-comment-text.outputs.sentry-link == ''
|
||||
uses: actions-cool/issues-helper@v3
|
||||
with:
|
||||
actions: "create-comment"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
body: |
|
||||
@${{ github.event.issue.user.login }}, the latest version of Bun is v${{ steps.add-labels.outputs.latest }}, but the standalone executable is running Bun v${{ steps.add-labels.outputs.outdated }}. When the CLI using Bun's single-file executable next updates it might be fixed.
|
||||
- name: Comment outdated
|
||||
if: steps.add-labels.outputs.is-outdated == 'true' && steps.add-labels.outputs.is-standalone != 'true' && github.event.label.name == 'crash' && steps.generate-comment-text.outputs.sentry-link == ''
|
||||
if: steps.add-labels.outputs.is-outdated == 'true' && github.event.label.name == 'crash' && steps.generate-comment-text.outputs.sentry-link == ''
|
||||
uses: actions-cool/issues-helper@v3
|
||||
with:
|
||||
actions: "create-comment"
|
||||
@@ -219,22 +139,8 @@ jobs:
|
||||
```sh
|
||||
bun upgrade
|
||||
```
|
||||
- name: Comment with Sentry Link and outdated version (standalone executable)
|
||||
if: steps.generate-comment-text.outputs.sentry-link != '' && github.event.label.name == 'crash' && steps.add-labels.outputs.is-outdated == 'true' && steps.add-labels.outputs.is-standalone == 'true'
|
||||
uses: actions-cool/issues-helper@v3
|
||||
with:
|
||||
actions: "create-comment"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
body: |
|
||||
@${{ github.event.issue.user.login }}, thank you for reporting this crash. The latest version of Bun is v${{ steps.add-labels.outputs.latest }}, but the standalone executable is running Bun v${{ steps.add-labels.outputs.outdated }}. When the CLI using Bun's single-file executable next updates it might be fixed.
|
||||
|
||||
For Bun's internal tracking, this issue is [${{ steps.generate-comment-text.outputs.sentry-id }}](${{ steps.generate-comment-text.outputs.sentry-link }}).
|
||||
|
||||
<!-- sentry-id: ${{ steps.generate-comment-text.outputs.sentry-id }} -->
|
||||
<!-- sentry-link: ${{ steps.generate-comment-text.outputs.sentry-link }} -->
|
||||
- name: Comment with Sentry Link and outdated version
|
||||
if: steps.generate-comment-text.outputs.sentry-link != '' && github.event.label.name == 'crash' && steps.add-labels.outputs.is-outdated == 'true' && steps.add-labels.outputs.is-standalone != 'true'
|
||||
if: steps.generate-comment-text.outputs.sentry-link != '' && github.event.label.name == 'crash' && steps.add-labels.outputs.is-outdated == 'true'
|
||||
uses: actions-cool/issues-helper@v3
|
||||
with:
|
||||
actions: "create-comment"
|
||||
|
||||
89
.github/workflows/on-submodule-update.yml
vendored
Normal file
89
.github/workflows/on-submodule-update.yml
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
name: Comment on updated submodule
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
paths:
|
||||
- "src/generated_versions_list.zig"
|
||||
- ".github/workflows/on-submodule-update.yml"
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
name: Comment
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository_owner == 'oven-sh' }}
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
steps:
|
||||
- name: Checkout current
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
src
|
||||
- name: Hash generated versions list
|
||||
id: hash
|
||||
run: |
|
||||
echo "hash=$(sha256sum src/generated_versions_list.zig | cut -d ' ' -f 1)" >> $GITHUB_OUTPUT
|
||||
- name: Checkout base
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.base_ref }}
|
||||
sparse-checkout: |
|
||||
src
|
||||
- name: Hash base
|
||||
id: base
|
||||
run: |
|
||||
echo "base=$(sha256sum src/generated_versions_list.zig | cut -d ' ' -f 1)" >> $GITHUB_OUTPUT
|
||||
- name: Compare
|
||||
id: compare
|
||||
run: |
|
||||
if [ "${{ steps.hash.outputs.hash }}" != "${{ steps.base.outputs.base }}" ]; then
|
||||
echo "changed=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "changed=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Find Comment
|
||||
id: comment
|
||||
uses: peter-evans/find-comment@v3
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
comment-author: github-actions[bot]
|
||||
body-includes: <!-- generated-comment submodule-updated -->
|
||||
- name: Write Warning Comment
|
||||
uses: peter-evans/create-or-update-comment@v4
|
||||
if: steps.compare.outputs.changed == 'true'
|
||||
with:
|
||||
comment-id: ${{ steps.comment.outputs.comment-id }}
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
edit-mode: replace
|
||||
body: |
|
||||
⚠️ **Warning:** @${{ github.actor }}, this PR has changes to submodule versions.
|
||||
|
||||
If this change was intentional, please ignore this message. If not, please undo changes to submodules and rebase your branch.
|
||||
|
||||
<!-- generated-comment submodule-updated -->
|
||||
- name: Add labels
|
||||
uses: actions-cool/issues-helper@v3
|
||||
if: steps.compare.outputs.changed == 'true'
|
||||
with:
|
||||
actions: "add-labels"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
labels: "changed-submodules"
|
||||
- name: Remove labels
|
||||
uses: actions-cool/issues-helper@v3
|
||||
if: steps.compare.outputs.changed == 'false'
|
||||
with:
|
||||
actions: "remove-labels"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
labels: "changed-submodules"
|
||||
- name: Delete outdated comment
|
||||
uses: actions-cool/issues-helper@v3
|
||||
if: steps.compare.outputs.changed == 'false' && steps.comment.outputs.comment-id != ''
|
||||
with:
|
||||
actions: "delete-comment"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
comment-id: ${{ steps.comment.outputs.comment-id }}
|
||||
2
.github/workflows/update-cares.yml
vendored
2
.github/workflows/update-cares.yml
vendored
@@ -80,7 +80,7 @@ jobs:
|
||||
|
||||
- name: Create Pull Request
|
||||
if: success() && steps.check-version.outputs.current != steps.check-version.outputs.latest
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
add-paths: |
|
||||
|
||||
4
.github/workflows/update-hdrhistogram.yml
vendored
4
.github/workflows/update-hdrhistogram.yml
vendored
@@ -55,7 +55,7 @@ jobs:
|
||||
echo "Error: Could not fetch SHA for tag $LATEST_TAG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Try to get commit SHA from tag object (for annotated tags)
|
||||
# If it fails, assume it's a lightweight tag pointing directly to commit
|
||||
LATEST_SHA=$(curl -sL "https://api.github.com/repos/HdrHistogram/HdrHistogram_c/git/tags/$LATEST_TAG_SHA" 2>/dev/null | jq -r '.object.sha // empty')
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
|
||||
- name: Create Pull Request
|
||||
if: success() && steps.check-version.outputs.current != steps.check-version.outputs.latest
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
add-paths: |
|
||||
|
||||
4
.github/workflows/update-highway.yml
vendored
4
.github/workflows/update-highway.yml
vendored
@@ -58,7 +58,7 @@ jobs:
|
||||
|
||||
TAG_OBJECT_SHA=$(echo "$TAG_REF" | jq -r '.object.sha')
|
||||
TAG_OBJECT_TYPE=$(echo "$TAG_REF" | jq -r '.object.type')
|
||||
|
||||
|
||||
if [ -z "$TAG_OBJECT_SHA" ] || [ "$TAG_OBJECT_SHA" = "null" ]; then
|
||||
echo "Error: Could not fetch SHA for tag $LATEST_TAG"
|
||||
exit 1
|
||||
@@ -99,7 +99,7 @@ jobs:
|
||||
|
||||
- name: Create Pull Request
|
||||
if: success() && steps.check-version.outputs.current != steps.check-version.outputs.latest
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
add-paths: |
|
||||
|
||||
2
.github/workflows/update-libarchive.yml
vendored
2
.github/workflows/update-libarchive.yml
vendored
@@ -80,7 +80,7 @@ jobs:
|
||||
|
||||
- name: Create Pull Request
|
||||
if: success() && steps.check-version.outputs.current != steps.check-version.outputs.latest
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
add-paths: |
|
||||
|
||||
2
.github/workflows/update-libdeflate.yml
vendored
2
.github/workflows/update-libdeflate.yml
vendored
@@ -80,7 +80,7 @@ jobs:
|
||||
|
||||
- name: Create Pull Request
|
||||
if: success() && steps.check-version.outputs.current != steps.check-version.outputs.latest
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
add-paths: |
|
||||
|
||||
6
.github/workflows/update-lolhtml.yml
vendored
6
.github/workflows/update-lolhtml.yml
vendored
@@ -55,12 +55,12 @@ jobs:
|
||||
TAG_REF_RESPONSE=$(curl -sL "https://api.github.com/repos/cloudflare/lol-html/git/refs/tags/$LATEST_TAG")
|
||||
LATEST_TAG_SHA=$(echo "$TAG_REF_RESPONSE" | jq -r '.object.sha')
|
||||
TAG_OBJECT_TYPE=$(echo "$TAG_REF_RESPONSE" | jq -r '.object.type')
|
||||
|
||||
|
||||
if [ -z "$LATEST_TAG_SHA" ] || [ "$LATEST_TAG_SHA" = "null" ]; then
|
||||
echo "Error: Could not fetch SHA for tag $LATEST_TAG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
if [ "$TAG_OBJECT_TYPE" = "tag" ]; then
|
||||
# This is an annotated tag, we need to get the commit it points to
|
||||
LATEST_SHA=$(curl -sL "https://api.github.com/repos/cloudflare/lol-html/git/tags/$LATEST_TAG_SHA" | jq -r '.object.sha')
|
||||
@@ -92,7 +92,7 @@ jobs:
|
||||
|
||||
- name: Create Pull Request
|
||||
if: success() && steps.check-version.outputs.current != steps.check-version.outputs.latest
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
add-paths: |
|
||||
|
||||
4
.github/workflows/update-lshpack.yml
vendored
4
.github/workflows/update-lshpack.yml
vendored
@@ -59,7 +59,7 @@ jobs:
|
||||
|
||||
LATEST_TAG_SHA=$(echo "$TAG_REF" | jq -r '.object.sha')
|
||||
TAG_TYPE=$(echo "$TAG_REF" | jq -r '.object.type')
|
||||
|
||||
|
||||
if [ -z "$LATEST_TAG_SHA" ] || [ "$LATEST_TAG_SHA" = "null" ]; then
|
||||
echo "Error: Could not fetch SHA for tag $LATEST_TAG"
|
||||
exit 1
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
|
||||
- name: Create Pull Request
|
||||
if: success() && steps.check-version.outputs.current != steps.check-version.outputs.latest
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
add-paths: |
|
||||
|
||||
2
.github/workflows/update-sqlite3.yml
vendored
2
.github/workflows/update-sqlite3.yml
vendored
@@ -91,7 +91,7 @@ jobs:
|
||||
|
||||
- name: Create Pull Request
|
||||
if: success() && steps.check-version.outputs.current_num < steps.check-version.outputs.latest_num
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
add-paths: |
|
||||
|
||||
79
.github/workflows/update-vendor.yml
vendored
79
.github/workflows/update-vendor.yml
vendored
@@ -1,79 +0,0 @@
|
||||
name: Update vendor
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 4 * * 0"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
check-update:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
package:
|
||||
- elysia
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Check version
|
||||
id: check-version
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
# Extract the commit hash from the line after COMMIT
|
||||
current=$(bun -p '(await Bun.file("test/vendor.json").json()).filter(v=>v.package===process.argv[1])[0].tag' ${{ matrix.package }})
|
||||
repository=$(bun -p '(await Bun.file("test/vendor.json").json()).filter(v=>v.package===process.argv[1])[0].repository' ${{ matrix.package }} | cut -d'/' -f4,5)
|
||||
|
||||
if [ -z "$current" ]; then
|
||||
echo "Error: Could not find COMMIT line in test/vendor.json"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "current=$current" >> $GITHUB_OUTPUT
|
||||
echo "repository=$repository" >> $GITHUB_OUTPUT
|
||||
|
||||
LATEST_RELEASE=$(curl -sL https://api.github.com/repos/${repository}/releases/latest)
|
||||
if [ -z "$LATEST_RELEASE" ]; then
|
||||
echo "Error: Failed to fetch latest release from GitHub API"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
LATEST_TAG=$(echo "$LATEST_RELEASE" | jq -r '.tag_name')
|
||||
if [ -z "$LATEST_TAG" ] || [ "$LATEST_TAG" = "null" ]; then
|
||||
echo "Error: Could not extract tag name from GitHub API response"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "latest=$LATEST_TAG" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Update version if needed
|
||||
if: success() && steps.check-version.outputs.current != steps.check-version.outputs.latest
|
||||
run: |
|
||||
set -euo pipefail
|
||||
bun -e 'await Bun.write("test/vendor.json", JSON.stringify((await Bun.file("test/vendor.json").json()).map(v=>{if(v.package===process.argv[1])v.tag=process.argv[2];return v;}), null, 2) + "\n")' ${{ matrix.package }} ${{ steps.check-version.outputs.latest }}
|
||||
|
||||
- name: Create Pull Request
|
||||
if: success() && steps.check-version.outputs.current != steps.check-version.outputs.latest
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
add-paths: |
|
||||
test/vendor.json
|
||||
commit-message: "deps: update ${{ matrix.package }} to ${{ steps.check-version.outputs.latest }} (${{ steps.check-version.outputs.latest }})"
|
||||
title: "deps: update ${{ matrix.package }} to ${{ steps.check-version.outputs.latest }}"
|
||||
delete-branch: true
|
||||
branch: deps/update-${{ matrix.package }}-${{ github.run_number }}
|
||||
body: |
|
||||
## What does this PR do?
|
||||
|
||||
Updates ${{ matrix.package }} to version ${{ steps.check-version.outputs.latest }}
|
||||
|
||||
Compare: https://github.com/${{ steps.check-version.outputs.repository }}/compare/${{ steps.check-version.outputs.current }}...${{ steps.check-version.outputs.latest }}
|
||||
|
||||
Auto-updated by [this workflow](https://github.com/oven-sh/bun/actions/workflows/update-vendor.yml)
|
||||
2
.github/workflows/update-zstd.yml
vendored
2
.github/workflows/update-zstd.yml
vendored
@@ -80,7 +80,7 @@ jobs:
|
||||
|
||||
- name: Create Pull Request
|
||||
if: success() && steps.check-version.outputs.current != steps.check-version.outputs.latest
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
add-paths: |
|
||||
|
||||
5
.github/workflows/vscode-release.yml
vendored
5
.github/workflows/vscode-release.yml
vendored
@@ -45,8 +45,3 @@ jobs:
|
||||
env:
|
||||
VSCE_PAT: ${{ secrets.VSCODE_EXTENSION }}
|
||||
working-directory: packages/bun-vscode/extension
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bun-vscode-${{ github.event.inputs.version }}.vsix
|
||||
path: packages/bun-vscode/extension/bun-vscode-${{ github.event.inputs.version }}.vsix
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -186,7 +186,4 @@ scratch*.{js,ts,tsx,cjs,mjs}
|
||||
|
||||
*.bun-build
|
||||
|
||||
scripts/lldb-inline
|
||||
|
||||
# We regenerate these in all the build scripts
|
||||
cmake/sources/*.txt
|
||||
scripts/lldb-inline
|
||||
11
.vscode/launch.json
generated
vendored
11
.vscode/launch.json
generated
vendored
@@ -25,9 +25,6 @@
|
||||
// "BUN_JSC_validateExceptionChecks": "1",
|
||||
// "BUN_JSC_dumpSimulatedThrows": "1",
|
||||
// "BUN_JSC_unexpectedExceptionStackTraceLimit": "20",
|
||||
// "BUN_DESTRUCT_VM_ON_EXIT": "1",
|
||||
// "ASAN_OPTIONS": "allow_user_segv_handler=1:disable_coredump=0:detect_leaks=1:abort_on_error=1",
|
||||
// "LSAN_OPTIONS": "malloc_context_size=100:print_suppressions=1:suppressions=${workspaceFolder}/test/leaksan.supp",
|
||||
},
|
||||
"console": "internalConsole",
|
||||
"sourceMap": {
|
||||
@@ -60,17 +57,11 @@
|
||||
"name": "bun run [file]",
|
||||
"program": "${workspaceFolder}/build/debug/bun-debug",
|
||||
"args": ["${file}"],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"cwd": "${fileDirname}",
|
||||
"env": {
|
||||
"FORCE_COLOR": "0",
|
||||
"BUN_DEBUG_QUIET_LOGS": "1",
|
||||
"BUN_GARBAGE_COLLECTOR_LEVEL": "2",
|
||||
// "BUN_JSC_validateExceptionChecks": "1",
|
||||
// "BUN_JSC_dumpSimulatedThrows": "1",
|
||||
// "BUN_JSC_unexpectedExceptionStackTraceLimit": "20",
|
||||
// "BUN_DESTRUCT_VM_ON_EXIT": "1",
|
||||
// "ASAN_OPTIONS": "allow_user_segv_handler=1:disable_coredump=0:detect_leaks=1:abort_on_error=1",
|
||||
// "LSAN_OPTIONS": "malloc_context_size=100:print_suppressions=1:suppressions=${workspaceFolder}/test/leaksan.supp",
|
||||
},
|
||||
"console": "internalConsole",
|
||||
"sourceMap": {
|
||||
|
||||
21
CLAUDE.md
21
CLAUDE.md
@@ -4,14 +4,18 @@ This is the Bun repository - an all-in-one JavaScript runtime & toolkit designed
|
||||
|
||||
### Build Commands
|
||||
|
||||
- **Build Bun**: `bun bd`
|
||||
- **Build debug version**: `bun bd`
|
||||
- Creates a debug build at `./build/debug/bun-debug`
|
||||
- **CRITICAL**: no need for a timeout, the build is really fast!
|
||||
- **CRITICAL**: DO NOT set a build timeout. Compilation takes ~5 minutes. Be patient.
|
||||
- **Run tests with your debug build**: `bun bd test <test-file>`
|
||||
- **CRITICAL**: Never use `bun test` directly - it won't include your changes
|
||||
- **Run any command with debug build**: `bun bd <command>`
|
||||
|
||||
Tip: Bun is already installed and in $PATH. The `bd` subcommand is a package.json script.
|
||||
### Other Build Variants
|
||||
|
||||
- `bun run build:release` - Release build
|
||||
|
||||
Address sanitizer is enabled by default in debug builds of Bun.
|
||||
|
||||
## Testing
|
||||
|
||||
@@ -39,11 +43,16 @@ Tests use Bun's Jest-compatible test runner with proper test fixtures:
|
||||
|
||||
```typescript
|
||||
import { test, expect } from "bun:test";
|
||||
import { bunEnv, bunExe, normalizeBunSnapshot, tempDir } from "harness";
|
||||
import {
|
||||
bunEnv,
|
||||
bunExe,
|
||||
normalizeBunSnapshot,
|
||||
tempDirWithFiles,
|
||||
} from "harness";
|
||||
|
||||
test("my feature", async () => {
|
||||
// Create temp directory with test files
|
||||
using dir = tempDir("test-prefix", {
|
||||
const dir = tempDirWithFiles("test-prefix", {
|
||||
"index.js": `console.log("hello");`,
|
||||
});
|
||||
|
||||
@@ -51,7 +60,7 @@ test("my feature", async () => {
|
||||
await using proc = Bun.spawn({
|
||||
cmd: [bunExe(), "index.js"],
|
||||
env: bunEnv,
|
||||
cwd: String(dir),
|
||||
cwd: dir,
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
|
||||
@@ -31,11 +31,6 @@ include(SetupCcache)
|
||||
parse_package_json(VERSION_VARIABLE DEFAULT_VERSION)
|
||||
optionx(VERSION STRING "The version of Bun" DEFAULT ${DEFAULT_VERSION})
|
||||
project(Bun VERSION ${VERSION})
|
||||
|
||||
# Bun uses C++23, which is compatible with BoringSSL's C++17 requirement
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
include(Options)
|
||||
include(CompilerFlags)
|
||||
|
||||
@@ -48,9 +43,6 @@ include(SetupEsbuild)
|
||||
include(SetupZig)
|
||||
include(SetupRust)
|
||||
|
||||
# Generate dependency versions header
|
||||
include(GenerateDependencyVersions)
|
||||
|
||||
# --- Targets ---
|
||||
|
||||
include(BuildBun)
|
||||
|
||||
@@ -21,7 +21,7 @@ $ sudo pacman -S base-devel ccache cmake git go libiconv libtool make ninja pkg-
|
||||
```
|
||||
|
||||
```bash#Fedora
|
||||
$ sudo dnf install cargo clang19 llvm19 lld19 ccache cmake git golang libtool ninja-build pkg-config rustc ruby libatomic-static libstdc++-static sed unzip which libicu-devel 'perl(Math::BigInt)'
|
||||
$ sudo dnf install cargo ccache cmake git golang libtool ninja-build pkg-config rustc ruby libatomic-static libstdc++-static sed unzip which libicu-devel 'perl(Math::BigInt)'
|
||||
```
|
||||
|
||||
```bash#openSUSE Tumbleweed
|
||||
@@ -223,8 +223,8 @@ $ git clone https://github.com/oven-sh/WebKit vendor/WebKit
|
||||
$ git -C vendor/WebKit checkout <commit_hash>
|
||||
|
||||
# Make a debug build of JSC. This will output build artifacts in ./vendor/WebKit/WebKitBuild/Debug
|
||||
# Optionally, you can use `bun run jsc:build` for a release build
|
||||
$ bun run jsc:build:debug && rm vendor/WebKit/WebKitBuild/Debug/JavaScriptCore/DerivedSources/inspector/InspectorProtocolObjects.h
|
||||
# Optionally, you can use `make jsc` for a release build
|
||||
$ make jsc-debug && rm vendor/WebKit/WebKitBuild/Debug/JavaScriptCore/DerivedSources/inspector/InspectorProtocolObjects.h
|
||||
|
||||
# After an initial run of `make jsc-debug`, you can rebuild JSC with:
|
||||
$ cmake --build vendor/WebKit/WebKitBuild/Debug --target jsc && rm vendor/WebKit/WebKitBuild/Debug/JavaScriptCore/DerivedSources/inspector/InspectorProtocolObjects.h
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
// Benchmark for object fast path optimization in postMessage with Workers
|
||||
|
||||
import { bench, run } from "mitata";
|
||||
import { Worker } from "node:worker_threads";
|
||||
|
||||
const extraProperties = {
|
||||
a: "a!",
|
||||
b: "b!",
|
||||
"second": "c!",
|
||||
bool: true,
|
||||
nully: null,
|
||||
undef: undefined,
|
||||
int: 0,
|
||||
double: 1.234,
|
||||
falsy: false,
|
||||
};
|
||||
|
||||
const objects = {
|
||||
small: { property: "Hello world", ...extraProperties },
|
||||
medium: {
|
||||
property: Buffer.alloc("Hello World!!!".length * 1024, "Hello World!!!").toString(),
|
||||
...extraProperties,
|
||||
},
|
||||
large: {
|
||||
property: Buffer.alloc("Hello World!!!".length * 1024 * 256, "Hello World!!!").toString(),
|
||||
...extraProperties,
|
||||
},
|
||||
};
|
||||
|
||||
let worker;
|
||||
let receivedCount = new Int32Array(new SharedArrayBuffer(4));
|
||||
let sentCount = 0;
|
||||
|
||||
function createWorker() {
|
||||
const workerCode = `
|
||||
import { parentPort, workerData } from "node:worker_threads";
|
||||
|
||||
let int = workerData;
|
||||
|
||||
parentPort?.on("message", data => {
|
||||
switch (data.property.length) {
|
||||
case ${objects.small.property.length}:
|
||||
case ${objects.medium.property.length}:
|
||||
case ${objects.large.property.length}: {
|
||||
if (
|
||||
data.a === "a!" &&
|
||||
data.b === "b!" &&
|
||||
data.second === "c!" &&
|
||||
data.bool === true &&
|
||||
data.nully === null &&
|
||||
data.undef === undefined &&
|
||||
data.int === 0 &&
|
||||
data.double === 1.234 &&
|
||||
data.falsy === false) {
|
||||
Atomics.add(int, 0, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
default: {
|
||||
throw new Error("Invalid data object: " + JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
`;
|
||||
|
||||
worker = new Worker(workerCode, { eval: true, workerData: receivedCount });
|
||||
|
||||
worker.on("message", confirmationId => {});
|
||||
|
||||
worker.on("error", error => {
|
||||
console.error("Worker error:", error);
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize worker before running benchmarks
|
||||
createWorker();
|
||||
|
||||
function fmt(int) {
|
||||
if (int < 1000) {
|
||||
return `${int} chars`;
|
||||
}
|
||||
|
||||
if (int < 100000) {
|
||||
return `${(int / 1024) | 0} KB`;
|
||||
}
|
||||
|
||||
return `${(int / 1024 / 1024) | 0} MB`;
|
||||
}
|
||||
|
||||
// Benchmark postMessage with pure strings (uses fast path)
|
||||
bench("postMessage({ prop: " + fmt(objects.small.property.length) + " string, ...9 more props })", async () => {
|
||||
sentCount++;
|
||||
worker.postMessage(objects.small);
|
||||
});
|
||||
|
||||
bench("postMessage({ prop: " + fmt(objects.medium.property.length) + " string, ...9 more props })", async () => {
|
||||
sentCount++;
|
||||
worker.postMessage(objects.medium);
|
||||
});
|
||||
|
||||
bench("postMessage({ prop: " + fmt(objects.large.property.length) + " string, ...9 more props })", async () => {
|
||||
sentCount++;
|
||||
worker.postMessage(objects.large);
|
||||
});
|
||||
|
||||
await run();
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 5000));
|
||||
|
||||
if (receivedCount[0] !== sentCount) {
|
||||
throw new Error("Expected " + receivedCount[0] + " to equal " + sentCount);
|
||||
}
|
||||
|
||||
// Cleanup worker
|
||||
worker?.terminate();
|
||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
const isBun = typeof globalThis?.Bun?.sql !== "undefined";
|
||||
import postgres from "postgres";
|
||||
const sql = isBun ? Bun.sql : postgres();
|
||||
const sql = isBun ? Bun.sql : postgres;
|
||||
|
||||
// Create the table if it doesn't exist
|
||||
await sql`
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
const isBun = typeof globalThis?.Bun?.sql !== "undefined";
|
||||
let conn;
|
||||
let sql;
|
||||
import * as mariadb from "mariadb";
|
||||
import * as mysql2 from "mysql2/promise";
|
||||
let useMYSQL2 = false;
|
||||
if (process.argv.includes("--mysql2")) {
|
||||
useMYSQL2 = true;
|
||||
}
|
||||
if (isBun) {
|
||||
sql = new Bun.SQL({
|
||||
adapter: "mysql",
|
||||
database: "test",
|
||||
username: "root",
|
||||
});
|
||||
} else {
|
||||
const pool = (useMYSQL2 ? mysql2 : mariadb).createPool({
|
||||
// Add your MariaDB connection details here
|
||||
user: "root",
|
||||
database: "test",
|
||||
});
|
||||
conn = await pool.getConnection();
|
||||
}
|
||||
|
||||
if (isBun) {
|
||||
// Initialize the benchmark table (equivalent to initFct)
|
||||
await sql`DROP TABLE IF EXISTS test100`;
|
||||
await sql`CREATE TABLE test100 (i1 int,i2 int,i3 int,i4 int,i5 int,i6 int,i7 int,i8 int,i9 int,i10 int,i11 int,i12 int,i13 int,i14 int,i15 int,i16 int,i17 int,i18 int,i19 int,i20 int,i21 int,i22 int,i23 int,i24 int,i25 int,i26 int,i27 int,i28 int,i29 int,i30 int,i31 int,i32 int,i33 int,i34 int,i35 int,i36 int,i37 int,i38 int,i39 int,i40 int,i41 int,i42 int,i43 int,i44 int,i45 int,i46 int,i47 int,i48 int,i49 int,i50 int,i51 int,i52 int,i53 int,i54 int,i55 int,i56 int,i57 int,i58 int,i59 int,i60 int,i61 int,i62 int,i63 int,i64 int,i65 int,i66 int,i67 int,i68 int,i69 int,i70 int,i71 int,i72 int,i73 int,i74 int,i75 int,i76 int,i77 int,i78 int,i79 int,i80 int,i81 int,i82 int,i83 int,i84 int,i85 int,i86 int,i87 int,i88 int,i89 int,i90 int,i91 int,i92 int,i93 int,i94 int,i95 int,i96 int,i97 int,i98 int,i99 int,i100 int)`;
|
||||
await sql`INSERT INTO test100 value (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100)`;
|
||||
} else {
|
||||
// Initialize the benchmark table (equivalent to initFct)
|
||||
await conn.query("DROP TABLE IF EXISTS test100");
|
||||
await conn.query(
|
||||
"CREATE TABLE test100 (i1 int,i2 int,i3 int,i4 int,i5 int,i6 int,i7 int,i8 int,i9 int,i10 int,i11 int,i12 int,i13 int,i14 int,i15 int,i16 int,i17 int,i18 int,i19 int,i20 int,i21 int,i22 int,i23 int,i24 int,i25 int,i26 int,i27 int,i28 int,i29 int,i30 int,i31 int,i32 int,i33 int,i34 int,i35 int,i36 int,i37 int,i38 int,i39 int,i40 int,i41 int,i42 int,i43 int,i44 int,i45 int,i46 int,i47 int,i48 int,i49 int,i50 int,i51 int,i52 int,i53 int,i54 int,i55 int,i56 int,i57 int,i58 int,i59 int,i60 int,i61 int,i62 int,i63 int,i64 int,i65 int,i66 int,i67 int,i68 int,i69 int,i70 int,i71 int,i72 int,i73 int,i74 int,i75 int,i76 int,i77 int,i78 int,i79 int,i80 int,i81 int,i82 int,i83 int,i84 int,i85 int,i86 int,i87 int,i88 int,i89 int,i90 int,i91 int,i92 int,i93 int,i94 int,i95 int,i96 int,i97 int,i98 int,i99 int,i100 int)",
|
||||
);
|
||||
await conn.query(
|
||||
"INSERT INTO test100 value (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100)",
|
||||
);
|
||||
}
|
||||
// Run the benchmark (equivalent to benchFct)
|
||||
const type = isBun ? "Bun.SQL" : useMYSQL2 ? "mysql2" : "mariadb";
|
||||
console.time(type);
|
||||
let promises = [];
|
||||
|
||||
for (let i = 0; i < 100_000; i++) {
|
||||
if (isBun) {
|
||||
promises.push(sql`select * FROM test100`);
|
||||
} else {
|
||||
promises.push(conn.query("select * FROM test100"));
|
||||
}
|
||||
}
|
||||
await Promise.all(promises);
|
||||
console.timeEnd(type);
|
||||
|
||||
// Clean up connection
|
||||
if (!isBun && conn.release) {
|
||||
conn.release();
|
||||
}
|
||||
@@ -9,8 +9,6 @@
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"mariadb": "^3.4.5",
|
||||
"mysql2": "^3.14.3",
|
||||
"postgres": "^3.4.7"
|
||||
}
|
||||
}
|
||||
@@ -12,9 +12,6 @@ const scenarios = [
|
||||
{ alg: "sha1", digest: "base64" },
|
||||
{ alg: "sha256", digest: "hex" },
|
||||
{ alg: "sha256", digest: "base64" },
|
||||
{ alg: "blake2b512", digest: "hex" },
|
||||
{ alg: "sha512-224", digest: "hex" },
|
||||
{ alg: "sha512-256", digest: "hex" },
|
||||
];
|
||||
|
||||
for (const { alg, digest } of scenarios) {
|
||||
@@ -26,10 +23,6 @@ for (const { alg, digest } of scenarios) {
|
||||
bench(`${alg}-${digest} (Bun.CryptoHasher)`, () => {
|
||||
new Bun.CryptoHasher(alg).update(data).digest(digest);
|
||||
});
|
||||
|
||||
bench(`${alg}-${digest} (Bun.CryptoHasher.hash)`, () => {
|
||||
return Bun.CryptoHasher.hash(alg, data, digest);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "yaml-benchmark",
|
||||
"dependencies": {
|
||||
"js-yaml": "^4.1.0",
|
||||
"yaml": "^2.8.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
|
||||
|
||||
"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
|
||||
|
||||
"yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="],
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "yaml-benchmark",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"js-yaml": "^4.1.0",
|
||||
"yaml": "^2.8.1"
|
||||
}
|
||||
}
|
||||
@@ -1,368 +0,0 @@
|
||||
import { bench, group, run } from "../runner.mjs";
|
||||
import jsYaml from "js-yaml";
|
||||
import yaml from "yaml";
|
||||
|
||||
// Small YAML document
|
||||
const smallYaml = `
|
||||
name: John Doe
|
||||
age: 30
|
||||
email: john@example.com
|
||||
active: true
|
||||
`;
|
||||
|
||||
// Medium YAML document with nested structures
|
||||
const mediumYaml = `
|
||||
company: Acme Corp
|
||||
employees:
|
||||
- name: John Doe
|
||||
age: 30
|
||||
position: Developer
|
||||
skills:
|
||||
- JavaScript
|
||||
- TypeScript
|
||||
- Node.js
|
||||
- name: Jane Smith
|
||||
age: 28
|
||||
position: Designer
|
||||
skills:
|
||||
- Figma
|
||||
- Photoshop
|
||||
- Illustrator
|
||||
- name: Bob Johnson
|
||||
age: 35
|
||||
position: Manager
|
||||
skills:
|
||||
- Leadership
|
||||
- Communication
|
||||
- Planning
|
||||
settings:
|
||||
database:
|
||||
host: localhost
|
||||
port: 5432
|
||||
name: mydb
|
||||
cache:
|
||||
enabled: true
|
||||
ttl: 3600
|
||||
`;
|
||||
|
||||
// Large YAML document with complex structures
|
||||
const largeYaml = `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx-deployment
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.14.2
|
||||
ports:
|
||||
- containerPort: 80
|
||||
env:
|
||||
- name: ENV_VAR_1
|
||||
value: "value1"
|
||||
- name: ENV_VAR_2
|
||||
value: "value2"
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/nginx
|
||||
resources:
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: "1Gi"
|
||||
requests:
|
||||
cpu: "0.5"
|
||||
memory: "512Mi"
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: nginx-config
|
||||
items:
|
||||
- key: nginx.conf
|
||||
path: nginx.conf
|
||||
- key: mime.types
|
||||
path: mime.types
|
||||
nodeSelector:
|
||||
disktype: ssd
|
||||
tolerations:
|
||||
- key: "key1"
|
||||
operator: "Equal"
|
||||
value: "value1"
|
||||
effect: "NoSchedule"
|
||||
- key: "key2"
|
||||
operator: "Exists"
|
||||
effect: "NoExecute"
|
||||
affinity:
|
||||
nodeAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
nodeSelectorTerms:
|
||||
- matchExpressions:
|
||||
- key: kubernetes.io/e2e-az-name
|
||||
operator: In
|
||||
values:
|
||||
- e2e-az1
|
||||
- e2e-az2
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchExpressions:
|
||||
- key: app
|
||||
operator: In
|
||||
values:
|
||||
- web-store
|
||||
topologyKey: kubernetes.io/hostname
|
||||
`;
|
||||
|
||||
// YAML with anchors and references
|
||||
const yamlWithAnchors = `
|
||||
defaults: &defaults
|
||||
adapter: postgresql
|
||||
host: localhost
|
||||
port: 5432
|
||||
|
||||
development:
|
||||
<<: *defaults
|
||||
database: dev_db
|
||||
|
||||
test:
|
||||
<<: *defaults
|
||||
database: test_db
|
||||
|
||||
production:
|
||||
<<: *defaults
|
||||
database: prod_db
|
||||
host: prod.example.com
|
||||
`;
|
||||
|
||||
// Array of items
|
||||
const arrayYaml = `
|
||||
- id: 1
|
||||
name: Item 1
|
||||
price: 10.99
|
||||
tags: [electronics, gadgets]
|
||||
- id: 2
|
||||
name: Item 2
|
||||
price: 25.50
|
||||
tags: [books, education]
|
||||
- id: 3
|
||||
name: Item 3
|
||||
price: 5.00
|
||||
tags: [food, snacks]
|
||||
- id: 4
|
||||
name: Item 4
|
||||
price: 100.00
|
||||
tags: [electronics, computers]
|
||||
- id: 5
|
||||
name: Item 5
|
||||
price: 15.75
|
||||
tags: [clothing, accessories]
|
||||
`;
|
||||
|
||||
// Multiline strings
|
||||
const multilineYaml = `
|
||||
description: |
|
||||
This is a multiline string
|
||||
that preserves line breaks
|
||||
and indentation.
|
||||
|
||||
It can contain multiple paragraphs
|
||||
and special characters: !@#$%^&*()
|
||||
|
||||
folded: >
|
||||
This is a folded string
|
||||
where line breaks are converted
|
||||
to spaces unless there are
|
||||
|
||||
empty lines like above.
|
||||
plain: This is a plain string
|
||||
quoted: "This is a quoted string with \\"escapes\\""
|
||||
literal: 'This is a literal string with ''quotes'''
|
||||
`;
|
||||
|
||||
// Numbers and special values
|
||||
const numbersYaml = `
|
||||
integer: 42
|
||||
negative: -17
|
||||
float: 3.14159
|
||||
scientific: 1.23e-4
|
||||
infinity: .inf
|
||||
negativeInfinity: -.inf
|
||||
notANumber: .nan
|
||||
octal: 0o755
|
||||
hex: 0xFF
|
||||
binary: 0b1010
|
||||
`;
|
||||
|
||||
// Dates and timestamps
|
||||
const datesYaml = `
|
||||
date: 2024-01-15
|
||||
datetime: 2024-01-15T10:30:00Z
|
||||
timestamp: 2024-01-15 10:30:00.123456789 -05:00
|
||||
canonical: 2024-01-15T10:30:00.123456789Z
|
||||
`;
|
||||
|
||||
// Parse benchmarks
|
||||
group("parse small YAML", () => {
|
||||
if (typeof Bun !== "undefined" && Bun.YAML) {
|
||||
bench("Bun.YAML.parse", () => {
|
||||
globalThis.result = Bun.YAML.parse(smallYaml);
|
||||
});
|
||||
}
|
||||
|
||||
bench("js-yaml.load", () => {
|
||||
globalThis.result = jsYaml.load(smallYaml);
|
||||
});
|
||||
|
||||
bench("yaml.parse", () => {
|
||||
globalThis.result = yaml.parse(smallYaml);
|
||||
});
|
||||
});
|
||||
|
||||
group("parse medium YAML", () => {
|
||||
if (typeof Bun !== "undefined" && Bun.YAML) {
|
||||
bench("Bun.YAML.parse", () => {
|
||||
globalThis.result = Bun.YAML.parse(mediumYaml);
|
||||
});
|
||||
}
|
||||
|
||||
bench("js-yaml.load", () => {
|
||||
globalThis.result = jsYaml.load(mediumYaml);
|
||||
});
|
||||
|
||||
bench("yaml.parse", () => {
|
||||
globalThis.result = yaml.parse(mediumYaml);
|
||||
});
|
||||
});
|
||||
|
||||
group("parse large YAML", () => {
|
||||
if (typeof Bun !== "undefined" && Bun.YAML) {
|
||||
bench("Bun.YAML.parse", () => {
|
||||
globalThis.result = Bun.YAML.parse(largeYaml);
|
||||
});
|
||||
}
|
||||
|
||||
bench("js-yaml.load", () => {
|
||||
globalThis.result = jsYaml.load(largeYaml);
|
||||
});
|
||||
|
||||
bench("yaml.parse", () => {
|
||||
globalThis.result = yaml.parse(largeYaml);
|
||||
});
|
||||
});
|
||||
|
||||
group("parse YAML with anchors", () => {
|
||||
if (typeof Bun !== "undefined" && Bun.YAML) {
|
||||
bench("Bun.YAML.parse", () => {
|
||||
globalThis.result = Bun.YAML.parse(yamlWithAnchors);
|
||||
});
|
||||
}
|
||||
|
||||
bench("js-yaml.load", () => {
|
||||
globalThis.result = jsYaml.load(yamlWithAnchors);
|
||||
});
|
||||
|
||||
bench("yaml.parse", () => {
|
||||
globalThis.result = yaml.parse(yamlWithAnchors);
|
||||
});
|
||||
});
|
||||
|
||||
group("parse YAML array", () => {
|
||||
if (typeof Bun !== "undefined" && Bun.YAML) {
|
||||
bench("Bun.YAML.parse", () => {
|
||||
globalThis.result = Bun.YAML.parse(arrayYaml);
|
||||
});
|
||||
}
|
||||
|
||||
bench("js-yaml.load", () => {
|
||||
globalThis.result = jsYaml.load(arrayYaml);
|
||||
});
|
||||
|
||||
bench("yaml.parse", () => {
|
||||
globalThis.result = yaml.parse(arrayYaml);
|
||||
});
|
||||
});
|
||||
|
||||
group("parse YAML with multiline strings", () => {
|
||||
if (typeof Bun !== "undefined" && Bun.YAML) {
|
||||
bench("Bun.YAML.parse", () => {
|
||||
globalThis.result = Bun.YAML.parse(multilineYaml);
|
||||
});
|
||||
}
|
||||
|
||||
bench("js-yaml.load", () => {
|
||||
globalThis.result = jsYaml.load(multilineYaml);
|
||||
});
|
||||
|
||||
bench("yaml.parse", () => {
|
||||
globalThis.result = yaml.parse(multilineYaml);
|
||||
});
|
||||
});
|
||||
|
||||
group("parse YAML with numbers", () => {
|
||||
if (typeof Bun !== "undefined" && Bun.YAML) {
|
||||
bench("Bun.YAML.parse", () => {
|
||||
globalThis.result = Bun.YAML.parse(numbersYaml);
|
||||
});
|
||||
}
|
||||
|
||||
bench("js-yaml.load", () => {
|
||||
globalThis.result = jsYaml.load(numbersYaml);
|
||||
});
|
||||
|
||||
bench("yaml.parse", () => {
|
||||
globalThis.result = yaml.parse(numbersYaml);
|
||||
});
|
||||
});
|
||||
|
||||
group("parse YAML with dates", () => {
|
||||
if (typeof Bun !== "undefined" && Bun.YAML) {
|
||||
bench("Bun.YAML.parse", () => {
|
||||
globalThis.result = Bun.YAML.parse(datesYaml);
|
||||
});
|
||||
}
|
||||
|
||||
bench("js-yaml.load", () => {
|
||||
globalThis.result = jsYaml.load(datesYaml);
|
||||
});
|
||||
|
||||
bench("yaml.parse", () => {
|
||||
globalThis.result = yaml.parse(datesYaml);
|
||||
});
|
||||
});
|
||||
|
||||
// // Stringify benchmarks
|
||||
// const smallObjJs = jsYaml.load(smallYaml);
|
||||
// const mediumObjJs = jsYaml.load(mediumYaml);
|
||||
// const largeObjJs = jsYaml.load(largeYaml);
|
||||
|
||||
// group("stringify small object", () => {
|
||||
// bench("js-yaml.dump", () => {
|
||||
// globalThis.result = jsYaml.dump(smallObjJs);
|
||||
// });
|
||||
// });
|
||||
|
||||
// group("stringify medium object", () => {
|
||||
// bench("js-yaml.dump", () => {
|
||||
// globalThis.result = jsYaml.dump(mediumObjJs);
|
||||
// });
|
||||
// });
|
||||
|
||||
// group("stringify large object", () => {
|
||||
// bench("js-yaml.dump", () => {
|
||||
// globalThis.result = jsYaml.dump(largeObjJs);
|
||||
// });
|
||||
// });
|
||||
|
||||
await run();
|
||||
@@ -1,407 +0,0 @@
|
||||
import { bench, group, run } from "../runner.mjs";
|
||||
import jsYaml from "js-yaml";
|
||||
import yaml from "yaml";
|
||||
|
||||
// Small object
|
||||
const smallObject = {
|
||||
name: "John Doe",
|
||||
age: 30,
|
||||
email: "john@example.com",
|
||||
active: true,
|
||||
};
|
||||
|
||||
// Medium object with nested structures
|
||||
const mediumObject = {
|
||||
company: "Acme Corp",
|
||||
employees: [
|
||||
{
|
||||
name: "John Doe",
|
||||
age: 30,
|
||||
position: "Developer",
|
||||
skills: ["JavaScript", "TypeScript", "Node.js"],
|
||||
},
|
||||
{
|
||||
name: "Jane Smith",
|
||||
age: 28,
|
||||
position: "Designer",
|
||||
skills: ["Figma", "Photoshop", "Illustrator"],
|
||||
},
|
||||
{
|
||||
name: "Bob Johnson",
|
||||
age: 35,
|
||||
position: "Manager",
|
||||
skills: ["Leadership", "Communication", "Planning"],
|
||||
},
|
||||
],
|
||||
settings: {
|
||||
database: {
|
||||
host: "localhost",
|
||||
port: 5432,
|
||||
name: "mydb",
|
||||
},
|
||||
cache: {
|
||||
enabled: true,
|
||||
ttl: 3600,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Large object with complex structures
|
||||
const largeObject = {
|
||||
apiVersion: "apps/v1",
|
||||
kind: "Deployment",
|
||||
metadata: {
|
||||
name: "nginx-deployment",
|
||||
labels: {
|
||||
app: "nginx",
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
replicas: 3,
|
||||
selector: {
|
||||
matchLabels: {
|
||||
app: "nginx",
|
||||
},
|
||||
},
|
||||
template: {
|
||||
metadata: {
|
||||
labels: {
|
||||
app: "nginx",
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
containers: [
|
||||
{
|
||||
name: "nginx",
|
||||
image: "nginx:1.14.2",
|
||||
ports: [
|
||||
{
|
||||
containerPort: 80,
|
||||
},
|
||||
],
|
||||
env: [
|
||||
{
|
||||
name: "ENV_VAR_1",
|
||||
value: "value1",
|
||||
},
|
||||
{
|
||||
name: "ENV_VAR_2",
|
||||
value: "value2",
|
||||
},
|
||||
],
|
||||
volumeMounts: [
|
||||
{
|
||||
name: "config",
|
||||
mountPath: "/etc/nginx",
|
||||
},
|
||||
],
|
||||
resources: {
|
||||
limits: {
|
||||
cpu: "1",
|
||||
memory: "1Gi",
|
||||
},
|
||||
requests: {
|
||||
cpu: "0.5",
|
||||
memory: "512Mi",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
volumes: [
|
||||
{
|
||||
name: "config",
|
||||
configMap: {
|
||||
name: "nginx-config",
|
||||
items: [
|
||||
{
|
||||
key: "nginx.conf",
|
||||
path: "nginx.conf",
|
||||
},
|
||||
{
|
||||
key: "mime.types",
|
||||
path: "mime.types",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
nodeSelector: {
|
||||
disktype: "ssd",
|
||||
},
|
||||
tolerations: [
|
||||
{
|
||||
key: "key1",
|
||||
operator: "Equal",
|
||||
value: "value1",
|
||||
effect: "NoSchedule",
|
||||
},
|
||||
{
|
||||
key: "key2",
|
||||
operator: "Exists",
|
||||
effect: "NoExecute",
|
||||
},
|
||||
],
|
||||
affinity: {
|
||||
nodeAffinity: {
|
||||
requiredDuringSchedulingIgnoredDuringExecution: {
|
||||
nodeSelectorTerms: [
|
||||
{
|
||||
matchExpressions: [
|
||||
{
|
||||
key: "kubernetes.io/e2e-az-name",
|
||||
operator: "In",
|
||||
values: ["e2e-az1", "e2e-az2"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
podAntiAffinity: {
|
||||
preferredDuringSchedulingIgnoredDuringExecution: [
|
||||
{
|
||||
weight: 100,
|
||||
podAffinityTerm: {
|
||||
labelSelector: {
|
||||
matchExpressions: [
|
||||
{
|
||||
key: "app",
|
||||
operator: "In",
|
||||
values: ["web-store"],
|
||||
},
|
||||
],
|
||||
},
|
||||
topologyKey: "kubernetes.io/hostname",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Object with anchors and references (after resolution)
|
||||
const objectWithAnchors = {
|
||||
defaults: {
|
||||
adapter: "postgresql",
|
||||
host: "localhost",
|
||||
port: 5432,
|
||||
},
|
||||
development: {
|
||||
adapter: "postgresql",
|
||||
host: "localhost",
|
||||
port: 5432,
|
||||
database: "dev_db",
|
||||
},
|
||||
test: {
|
||||
adapter: "postgresql",
|
||||
host: "localhost",
|
||||
port: 5432,
|
||||
database: "test_db",
|
||||
},
|
||||
production: {
|
||||
adapter: "postgresql",
|
||||
host: "prod.example.com",
|
||||
port: 5432,
|
||||
database: "prod_db",
|
||||
},
|
||||
};
|
||||
|
||||
// Array of items
|
||||
const arrayObject = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Item 1",
|
||||
price: 10.99,
|
||||
tags: ["electronics", "gadgets"],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Item 2",
|
||||
price: 25.5,
|
||||
tags: ["books", "education"],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Item 3",
|
||||
price: 5.0,
|
||||
tags: ["food", "snacks"],
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Item 4",
|
||||
price: 100.0,
|
||||
tags: ["electronics", "computers"],
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Item 5",
|
||||
price: 15.75,
|
||||
tags: ["clothing", "accessories"],
|
||||
},
|
||||
];
|
||||
|
||||
// Multiline strings
|
||||
const multilineObject = {
|
||||
description:
|
||||
"This is a multiline string\nthat preserves line breaks\nand indentation.\n\nIt can contain multiple paragraphs\nand special characters: !@#$%^&*()\n",
|
||||
folded: "This is a folded string where line breaks are converted to spaces unless there are\nempty lines like above.",
|
||||
plain: "This is a plain string",
|
||||
quoted: 'This is a quoted string with "escapes"',
|
||||
literal: "This is a literal string with 'quotes'",
|
||||
};
|
||||
|
||||
// Numbers and special values
|
||||
const numbersObject = {
|
||||
integer: 42,
|
||||
negative: -17,
|
||||
float: 3.14159,
|
||||
scientific: 0.000123,
|
||||
infinity: Infinity,
|
||||
negativeInfinity: -Infinity,
|
||||
notANumber: NaN,
|
||||
octal: 493, // 0o755
|
||||
hex: 255, // 0xFF
|
||||
binary: 10, // 0b1010
|
||||
};
|
||||
|
||||
// Dates and timestamps
|
||||
const datesObject = {
|
||||
date: new Date("2024-01-15"),
|
||||
datetime: new Date("2024-01-15T10:30:00Z"),
|
||||
timestamp: new Date("2024-01-15T15:30:00.123456789Z"), // Adjusted for UTC-5
|
||||
canonical: new Date("2024-01-15T10:30:00.123456789Z"),
|
||||
};
|
||||
|
||||
// Stringify benchmarks
|
||||
group("stringify small object", () => {
|
||||
if (typeof Bun !== "undefined" && Bun.YAML) {
|
||||
bench("Bun.YAML.stringify", () => {
|
||||
return Bun.YAML.stringify(smallObject);
|
||||
});
|
||||
}
|
||||
|
||||
bench("js-yaml.dump", () => {
|
||||
return jsYaml.dump(smallObject);
|
||||
});
|
||||
|
||||
bench("yaml.stringify", () => {
|
||||
return yaml.stringify(smallObject);
|
||||
});
|
||||
});
|
||||
|
||||
group("stringify medium object", () => {
|
||||
if (typeof Bun !== "undefined" && Bun.YAML) {
|
||||
bench("Bun.YAML.stringify", () => {
|
||||
return Bun.YAML.stringify(mediumObject);
|
||||
});
|
||||
}
|
||||
|
||||
bench("js-yaml.dump", () => {
|
||||
return jsYaml.dump(mediumObject);
|
||||
});
|
||||
|
||||
bench("yaml.stringify", () => {
|
||||
return yaml.stringify(mediumObject);
|
||||
});
|
||||
});
|
||||
|
||||
group("stringify large object", () => {
|
||||
if (typeof Bun !== "undefined" && Bun.YAML) {
|
||||
bench("Bun.YAML.stringify", () => {
|
||||
return Bun.YAML.stringify(largeObject);
|
||||
});
|
||||
}
|
||||
|
||||
bench("js-yaml.dump", () => {
|
||||
return jsYaml.dump(largeObject);
|
||||
});
|
||||
|
||||
bench("yaml.stringify", () => {
|
||||
return yaml.stringify(largeObject);
|
||||
});
|
||||
});
|
||||
|
||||
group("stringify object with anchors", () => {
|
||||
if (typeof Bun !== "undefined" && Bun.YAML) {
|
||||
bench("Bun.YAML.stringify", () => {
|
||||
return Bun.YAML.stringify(objectWithAnchors);
|
||||
});
|
||||
}
|
||||
|
||||
bench("js-yaml.dump", () => {
|
||||
return jsYaml.dump(objectWithAnchors);
|
||||
});
|
||||
|
||||
bench("yaml.stringify", () => {
|
||||
return yaml.stringify(objectWithAnchors);
|
||||
});
|
||||
});
|
||||
|
||||
group("stringify array", () => {
|
||||
if (typeof Bun !== "undefined" && Bun.YAML) {
|
||||
bench("Bun.YAML.stringify", () => {
|
||||
return Bun.YAML.stringify(arrayObject);
|
||||
});
|
||||
}
|
||||
|
||||
bench("js-yaml.dump", () => {
|
||||
return jsYaml.dump(arrayObject);
|
||||
});
|
||||
|
||||
bench("yaml.stringify", () => {
|
||||
return yaml.stringify(arrayObject);
|
||||
});
|
||||
});
|
||||
|
||||
group("stringify object with multiline strings", () => {
|
||||
if (typeof Bun !== "undefined" && Bun.YAML) {
|
||||
bench("Bun.YAML.stringify", () => {
|
||||
return Bun.YAML.stringify(multilineObject);
|
||||
});
|
||||
}
|
||||
|
||||
bench("js-yaml.dump", () => {
|
||||
return jsYaml.dump(multilineObject);
|
||||
});
|
||||
|
||||
bench("yaml.stringify", () => {
|
||||
return yaml.stringify(multilineObject);
|
||||
});
|
||||
});
|
||||
|
||||
group("stringify object with numbers", () => {
|
||||
if (typeof Bun !== "undefined" && Bun.YAML) {
|
||||
bench("Bun.YAML.stringify", () => {
|
||||
return Bun.YAML.stringify(numbersObject);
|
||||
});
|
||||
}
|
||||
|
||||
bench("js-yaml.dump", () => {
|
||||
return jsYaml.dump(numbersObject);
|
||||
});
|
||||
|
||||
bench("yaml.stringify", () => {
|
||||
return yaml.stringify(numbersObject);
|
||||
});
|
||||
});
|
||||
|
||||
group("stringify object with dates", () => {
|
||||
if (typeof Bun !== "undefined" && Bun.YAML) {
|
||||
bench("Bun.YAML.stringify", () => {
|
||||
return Bun.YAML.stringify(datesObject);
|
||||
});
|
||||
}
|
||||
|
||||
bench("js-yaml.dump", () => {
|
||||
return jsYaml.dump(datesObject);
|
||||
});
|
||||
|
||||
bench("yaml.stringify", () => {
|
||||
return yaml.stringify(datesObject);
|
||||
});
|
||||
});
|
||||
|
||||
await run();
|
||||
21
build.zig
21
build.zig
@@ -48,7 +48,6 @@ const BunBuildOptions = struct {
|
||||
/// enable debug logs in release builds
|
||||
enable_logs: bool = false,
|
||||
enable_asan: bool,
|
||||
enable_valgrind: bool,
|
||||
tracy_callstack_depth: u16,
|
||||
reported_nodejs_version: Version,
|
||||
/// To make iterating on some '@embedFile's faster, we load them at runtime
|
||||
@@ -95,7 +94,6 @@ const BunBuildOptions = struct {
|
||||
opts.addOption(bool, "baseline", this.isBaseline());
|
||||
opts.addOption(bool, "enable_logs", this.enable_logs);
|
||||
opts.addOption(bool, "enable_asan", this.enable_asan);
|
||||
opts.addOption(bool, "enable_valgrind", this.enable_valgrind);
|
||||
opts.addOption([]const u8, "reported_nodejs_version", b.fmt("{}", .{this.reported_nodejs_version}));
|
||||
opts.addOption(bool, "zig_self_hosted_backend", this.no_llvm);
|
||||
opts.addOption(bool, "override_no_export_cpp_apis", this.override_no_export_cpp_apis);
|
||||
@@ -215,21 +213,26 @@ pub fn build(b: *Build) !void {
|
||||
var build_options = BunBuildOptions{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
|
||||
.os = os,
|
||||
.arch = arch,
|
||||
|
||||
.codegen_path = codegen_path,
|
||||
.codegen_embed = codegen_embed,
|
||||
.no_llvm = no_llvm,
|
||||
.override_no_export_cpp_apis = override_no_export_cpp_apis,
|
||||
|
||||
.version = try Version.parse(bun_version),
|
||||
.canary_revision = canary: {
|
||||
const rev = b.option(u32, "canary", "Treat this as a canary build") orelse 0;
|
||||
break :canary if (rev == 0) null else rev;
|
||||
},
|
||||
|
||||
.reported_nodejs_version = try Version.parse(
|
||||
b.option([]const u8, "reported_nodejs_version", "Reported Node.js version") orelse
|
||||
"0.0.0-unset",
|
||||
),
|
||||
|
||||
.sha = sha: {
|
||||
const sha_buildoption = b.option([]const u8, "sha", "Force the git sha");
|
||||
const sha_github = b.graph.env_map.get("GITHUB_SHA");
|
||||
@@ -265,10 +268,10 @@ pub fn build(b: *Build) !void {
|
||||
|
||||
break :sha sha;
|
||||
},
|
||||
|
||||
.tracy_callstack_depth = b.option(u16, "tracy_callstack_depth", "") orelse 10,
|
||||
.enable_logs = b.option(bool, "enable_logs", "Enable logs in release") orelse false,
|
||||
.enable_asan = b.option(bool, "enable_asan", "Enable asan") orelse false,
|
||||
.enable_valgrind = b.option(bool, "enable_valgrind", "Enable valgrind") orelse false,
|
||||
};
|
||||
|
||||
// zig build obj
|
||||
@@ -497,7 +500,6 @@ fn addMultiCheck(
|
||||
.codegen_path = root_build_options.codegen_path,
|
||||
.no_llvm = root_build_options.no_llvm,
|
||||
.enable_asan = root_build_options.enable_asan,
|
||||
.enable_valgrind = root_build_options.enable_valgrind,
|
||||
.override_no_export_cpp_apis = root_build_options.override_no_export_cpp_apis,
|
||||
};
|
||||
|
||||
@@ -585,15 +587,9 @@ pub fn addBunObject(b: *Build, opts: *BunBuildOptions) *Compile {
|
||||
.root_module = root,
|
||||
});
|
||||
configureObj(b, opts, obj);
|
||||
if (enableFastBuild(b)) obj.root_module.strip = true;
|
||||
return obj;
|
||||
}
|
||||
|
||||
fn enableFastBuild(b: *Build) bool {
|
||||
const val = b.graph.env_map.get("BUN_BUILD_FAST") orelse return false;
|
||||
return std.mem.eql(u8, val, "1");
|
||||
}
|
||||
|
||||
fn configureObj(b: *Build, opts: *BunBuildOptions, obj: *Compile) void {
|
||||
// Flags on root module get used for the compilation
|
||||
obj.root_module.omit_frame_pointer = false;
|
||||
@@ -604,7 +600,7 @@ fn configureObj(b: *Build, opts: *BunBuildOptions, obj: *Compile) void {
|
||||
// Object options
|
||||
obj.use_llvm = !opts.no_llvm;
|
||||
obj.use_lld = if (opts.os == .mac) false else !opts.no_llvm;
|
||||
if (opts.enable_asan and !enableFastBuild(b)) {
|
||||
if (opts.enable_asan) {
|
||||
if (@hasField(Build.Module, "sanitize_address")) {
|
||||
obj.root_module.sanitize_address = true;
|
||||
} else {
|
||||
@@ -634,7 +630,7 @@ fn configureObj(b: *Build, opts: *BunBuildOptions, obj: *Compile) void {
|
||||
obj.link_function_sections = true;
|
||||
obj.link_data_sections = true;
|
||||
|
||||
if (opts.optimize == .Debug and opts.enable_valgrind) {
|
||||
if (opts.optimize == .Debug) {
|
||||
obj.root_module.valgrind = true;
|
||||
}
|
||||
}
|
||||
@@ -743,7 +739,6 @@ fn addInternalImports(b: *Build, mod: *Module, opts: *BunBuildOptions) void {
|
||||
.{ .file = "node-fallbacks/url.js", .enable = opts.shouldEmbedCode() },
|
||||
.{ .file = "node-fallbacks/util.js", .enable = opts.shouldEmbedCode() },
|
||||
.{ .file = "node-fallbacks/zlib.js", .enable = opts.shouldEmbedCode() },
|
||||
.{ .file = "eval/feedback.ts", .enable = opts.shouldEmbedCode() },
|
||||
}) |entry| {
|
||||
if (!@hasField(@TypeOf(entry), "enable") or entry.enable) {
|
||||
const path = b.pathJoin(&.{ opts.codegen_path, entry.file });
|
||||
|
||||
2
bun.lock
2
bun.lock
@@ -40,8 +40,8 @@
|
||||
},
|
||||
},
|
||||
"overrides": {
|
||||
"@types/bun": "workspace:packages/@types/bun",
|
||||
"bun-types": "workspace:packages/bun-types",
|
||||
"@types/bun": "workspace:packages/@types/bun",
|
||||
},
|
||||
"packages": {
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="],
|
||||
|
||||
@@ -57,23 +57,6 @@ else()
|
||||
message(FATAL_ERROR "Unsupported architecture: ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
endif()
|
||||
|
||||
# Windows Code Signing Option
|
||||
if(WIN32)
|
||||
optionx(ENABLE_WINDOWS_CODESIGNING BOOL "Enable Windows code signing with DigiCert KeyLocker" DEFAULT OFF)
|
||||
|
||||
if(ENABLE_WINDOWS_CODESIGNING)
|
||||
message(STATUS "Windows code signing: ENABLED")
|
||||
|
||||
# Check for required environment variables
|
||||
if(NOT DEFINED ENV{SM_API_KEY})
|
||||
message(WARNING "SM_API_KEY not set - code signing may fail")
|
||||
endif()
|
||||
if(NOT DEFINED ENV{SM_CLIENT_CERT_FILE})
|
||||
message(WARNING "SM_CLIENT_CERT_FILE not set - code signing may fail")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(LINUX)
|
||||
if(EXISTS "/etc/alpine-release")
|
||||
set(DEFAULT_ABI "musl")
|
||||
@@ -114,10 +97,8 @@ endif()
|
||||
|
||||
if(DEBUG AND ((APPLE AND ARCH STREQUAL "aarch64") OR LINUX))
|
||||
set(DEFAULT_ASAN ON)
|
||||
set(DEFAULT_VALGRIND OFF)
|
||||
else()
|
||||
set(DEFAULT_ASAN OFF)
|
||||
set(DEFAULT_VALGRIND OFF)
|
||||
endif()
|
||||
|
||||
optionx(ENABLE_ASAN BOOL "If ASAN support should be enabled" DEFAULT ${DEFAULT_ASAN})
|
||||
|
||||
@@ -13,10 +13,7 @@
|
||||
},
|
||||
{
|
||||
"output": "JavaScriptSources.txt",
|
||||
"paths": [
|
||||
"src/js/**/*.{js,ts}",
|
||||
"src/install/PackageManager/scanner-entry.ts"
|
||||
]
|
||||
"paths": ["src/js/**/*.{js,ts}"]
|
||||
},
|
||||
{
|
||||
"output": "JavaScriptCodegenSources.txt",
|
||||
|
||||
22
cmake/sources/BakeRuntimeSources.txt
Normal file
22
cmake/sources/BakeRuntimeSources.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
src/bake/bake.d.ts
|
||||
src/bake/bake.private.d.ts
|
||||
src/bake/bun-framework-react/index.ts
|
||||
src/bake/client/css-reloader.ts
|
||||
src/bake/client/data-view.ts
|
||||
src/bake/client/error-serialization.ts
|
||||
src/bake/client/inspect.ts
|
||||
src/bake/client/JavaScriptSyntaxHighlighter.css
|
||||
src/bake/client/JavaScriptSyntaxHighlighter.ts
|
||||
src/bake/client/overlay.css
|
||||
src/bake/client/overlay.ts
|
||||
src/bake/client/stack-trace.ts
|
||||
src/bake/client/websocket.ts
|
||||
src/bake/debug.ts
|
||||
src/bake/DevServer.bind.ts
|
||||
src/bake/enums.ts
|
||||
src/bake/hmr-module.ts
|
||||
src/bake/hmr-runtime-client.ts
|
||||
src/bake/hmr-runtime-error.ts
|
||||
src/bake/hmr-runtime-server.ts
|
||||
src/bake/server/stack-trace-stub.ts
|
||||
src/bake/shared.ts
|
||||
7
cmake/sources/BindgenSources.txt
Normal file
7
cmake/sources/BindgenSources.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
src/bake.bind.ts
|
||||
src/bake/DevServer.bind.ts
|
||||
src/bun.js/api/BunObject.bind.ts
|
||||
src/bun.js/bindgen_test.bind.ts
|
||||
src/bun.js/bindings/NodeModuleModule.bind.ts
|
||||
src/bun.js/node/node_os.bind.ts
|
||||
src/fmt.bind.ts
|
||||
12
cmake/sources/BunErrorSources.txt
Normal file
12
cmake/sources/BunErrorSources.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
packages/bun-error/bun-error.css
|
||||
packages/bun-error/img/close.png
|
||||
packages/bun-error/img/error.png
|
||||
packages/bun-error/img/powered-by.png
|
||||
packages/bun-error/img/powered-by.webp
|
||||
packages/bun-error/index.tsx
|
||||
packages/bun-error/markdown.ts
|
||||
packages/bun-error/package.json
|
||||
packages/bun-error/runtime-error.ts
|
||||
packages/bun-error/sourcemap.ts
|
||||
packages/bun-error/stack-trace-parser.ts
|
||||
packages/bun-error/tsconfig.json
|
||||
15
cmake/sources/CSources.txt
Normal file
15
cmake/sources/CSources.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
packages/bun-usockets/src/bsd.c
|
||||
packages/bun-usockets/src/context.c
|
||||
packages/bun-usockets/src/crypto/openssl.c
|
||||
packages/bun-usockets/src/eventing/epoll_kqueue.c
|
||||
packages/bun-usockets/src/eventing/libuv.c
|
||||
packages/bun-usockets/src/loop.c
|
||||
packages/bun-usockets/src/quic.c
|
||||
packages/bun-usockets/src/socket.c
|
||||
packages/bun-usockets/src/udp.c
|
||||
src/asan-config.c
|
||||
src/bun.js/bindings/node/http/llhttp/api.c
|
||||
src/bun.js/bindings/node/http/llhttp/http.c
|
||||
src/bun.js/bindings/node/http/llhttp/llhttp.c
|
||||
src/bun.js/bindings/uv-posix-polyfills.c
|
||||
src/bun.js/bindings/uv-posix-stubs.c
|
||||
500
cmake/sources/CxxSources.txt
Normal file
500
cmake/sources/CxxSources.txt
Normal file
@@ -0,0 +1,500 @@
|
||||
packages/bun-usockets/src/crypto/root_certs.cpp
|
||||
packages/bun-usockets/src/crypto/sni_tree.cpp
|
||||
src/bake/BakeGlobalObject.cpp
|
||||
src/bake/BakeProduction.cpp
|
||||
src/bake/BakeSourceProvider.cpp
|
||||
src/bun.js/bindings/ActiveDOMCallback.cpp
|
||||
src/bun.js/bindings/AsymmetricKeyValue.cpp
|
||||
src/bun.js/bindings/AsyncContextFrame.cpp
|
||||
src/bun.js/bindings/Base64Helpers.cpp
|
||||
src/bun.js/bindings/bindings.cpp
|
||||
src/bun.js/bindings/blob.cpp
|
||||
src/bun.js/bindings/bun-simdutf.cpp
|
||||
src/bun.js/bindings/bun-spawn.cpp
|
||||
src/bun.js/bindings/BunClientData.cpp
|
||||
src/bun.js/bindings/BunCommonStrings.cpp
|
||||
src/bun.js/bindings/BunDebugger.cpp
|
||||
src/bun.js/bindings/BunGCOutputConstraint.cpp
|
||||
src/bun.js/bindings/BunGlobalScope.cpp
|
||||
src/bun.js/bindings/BunHttp2CommonStrings.cpp
|
||||
src/bun.js/bindings/BunInjectedScriptHost.cpp
|
||||
src/bun.js/bindings/BunInspector.cpp
|
||||
src/bun.js/bindings/BunJSCEventLoop.cpp
|
||||
src/bun.js/bindings/BunObject.cpp
|
||||
src/bun.js/bindings/BunPlugin.cpp
|
||||
src/bun.js/bindings/BunProcess.cpp
|
||||
src/bun.js/bindings/BunString.cpp
|
||||
src/bun.js/bindings/BunWorkerGlobalScope.cpp
|
||||
src/bun.js/bindings/c-bindings.cpp
|
||||
src/bun.js/bindings/CallSite.cpp
|
||||
src/bun.js/bindings/CallSitePrototype.cpp
|
||||
src/bun.js/bindings/CatchScopeBinding.cpp
|
||||
src/bun.js/bindings/CodeCoverage.cpp
|
||||
src/bun.js/bindings/ConsoleObject.cpp
|
||||
src/bun.js/bindings/Cookie.cpp
|
||||
src/bun.js/bindings/CookieMap.cpp
|
||||
src/bun.js/bindings/coroutine.cpp
|
||||
src/bun.js/bindings/CPUFeatures.cpp
|
||||
src/bun.js/bindings/decodeURIComponentSIMD.cpp
|
||||
src/bun.js/bindings/DOMException.cpp
|
||||
src/bun.js/bindings/DOMFormData.cpp
|
||||
src/bun.js/bindings/DOMURL.cpp
|
||||
src/bun.js/bindings/DOMWrapperWorld.cpp
|
||||
src/bun.js/bindings/DoubleFormatter.cpp
|
||||
src/bun.js/bindings/EncodeURIComponent.cpp
|
||||
src/bun.js/bindings/EncodingTables.cpp
|
||||
src/bun.js/bindings/ErrorCode.cpp
|
||||
src/bun.js/bindings/ErrorStackFrame.cpp
|
||||
src/bun.js/bindings/ErrorStackTrace.cpp
|
||||
src/bun.js/bindings/EventLoopTaskNoContext.cpp
|
||||
src/bun.js/bindings/ExposeNodeModuleGlobals.cpp
|
||||
src/bun.js/bindings/ffi.cpp
|
||||
src/bun.js/bindings/helpers.cpp
|
||||
src/bun.js/bindings/highway_strings.cpp
|
||||
src/bun.js/bindings/HTMLEntryPoint.cpp
|
||||
src/bun.js/bindings/ImportMetaObject.cpp
|
||||
src/bun.js/bindings/inlines.cpp
|
||||
src/bun.js/bindings/InspectorBunFrontendDevServerAgent.cpp
|
||||
src/bun.js/bindings/InspectorHTTPServerAgent.cpp
|
||||
src/bun.js/bindings/InspectorLifecycleAgent.cpp
|
||||
src/bun.js/bindings/InspectorTestReporterAgent.cpp
|
||||
src/bun.js/bindings/InternalForTesting.cpp
|
||||
src/bun.js/bindings/InternalModuleRegistry.cpp
|
||||
src/bun.js/bindings/IPC.cpp
|
||||
src/bun.js/bindings/isBuiltinModule.cpp
|
||||
src/bun.js/bindings/JS2Native.cpp
|
||||
src/bun.js/bindings/JSBigIntBinding.cpp
|
||||
src/bun.js/bindings/JSBuffer.cpp
|
||||
src/bun.js/bindings/JSBufferEncodingType.cpp
|
||||
src/bun.js/bindings/JSBufferList.cpp
|
||||
src/bun.js/bindings/JSBundlerPlugin.cpp
|
||||
src/bun.js/bindings/JSBunRequest.cpp
|
||||
src/bun.js/bindings/JSCommonJSExtensions.cpp
|
||||
src/bun.js/bindings/JSCommonJSModule.cpp
|
||||
src/bun.js/bindings/JSCTaskScheduler.cpp
|
||||
src/bun.js/bindings/JSCTestingHelpers.cpp
|
||||
src/bun.js/bindings/JSDOMExceptionHandling.cpp
|
||||
src/bun.js/bindings/JSDOMFile.cpp
|
||||
src/bun.js/bindings/JSDOMGlobalObject.cpp
|
||||
src/bun.js/bindings/JSDOMWrapper.cpp
|
||||
src/bun.js/bindings/JSDOMWrapperCache.cpp
|
||||
src/bun.js/bindings/JSEnvironmentVariableMap.cpp
|
||||
src/bun.js/bindings/JSFFIFunction.cpp
|
||||
src/bun.js/bindings/JSMockFunction.cpp
|
||||
src/bun.js/bindings/JSNextTickQueue.cpp
|
||||
src/bun.js/bindings/JSNodePerformanceHooksHistogram.cpp
|
||||
src/bun.js/bindings/JSNodePerformanceHooksHistogramConstructor.cpp
|
||||
src/bun.js/bindings/JSNodePerformanceHooksHistogramPrototype.cpp
|
||||
src/bun.js/bindings/JSPropertyIterator.cpp
|
||||
src/bun.js/bindings/JSS3File.cpp
|
||||
src/bun.js/bindings/JSSocketAddressDTO.cpp
|
||||
src/bun.js/bindings/JSStringDecoder.cpp
|
||||
src/bun.js/bindings/JSWrappingFunction.cpp
|
||||
src/bun.js/bindings/JSX509Certificate.cpp
|
||||
src/bun.js/bindings/JSX509CertificateConstructor.cpp
|
||||
src/bun.js/bindings/JSX509CertificatePrototype.cpp
|
||||
src/bun.js/bindings/linux_perf_tracing.cpp
|
||||
src/bun.js/bindings/MarkingConstraint.cpp
|
||||
src/bun.js/bindings/ModuleLoader.cpp
|
||||
src/bun.js/bindings/napi_external.cpp
|
||||
src/bun.js/bindings/napi_finalizer.cpp
|
||||
src/bun.js/bindings/napi_handle_scope.cpp
|
||||
src/bun.js/bindings/napi_type_tag.cpp
|
||||
src/bun.js/bindings/napi.cpp
|
||||
src/bun.js/bindings/NapiClass.cpp
|
||||
src/bun.js/bindings/NapiRef.cpp
|
||||
src/bun.js/bindings/NapiWeakValue.cpp
|
||||
src/bun.js/bindings/ncrpyto_engine.cpp
|
||||
src/bun.js/bindings/ncrypto.cpp
|
||||
src/bun.js/bindings/node/crypto/CryptoDhJob.cpp
|
||||
src/bun.js/bindings/node/crypto/CryptoGenDhKeyPair.cpp
|
||||
src/bun.js/bindings/node/crypto/CryptoGenDsaKeyPair.cpp
|
||||
src/bun.js/bindings/node/crypto/CryptoGenEcKeyPair.cpp
|
||||
src/bun.js/bindings/node/crypto/CryptoGenKeyPair.cpp
|
||||
src/bun.js/bindings/node/crypto/CryptoGenNidKeyPair.cpp
|
||||
src/bun.js/bindings/node/crypto/CryptoGenRsaKeyPair.cpp
|
||||
src/bun.js/bindings/node/crypto/CryptoHkdf.cpp
|
||||
src/bun.js/bindings/node/crypto/CryptoKeygen.cpp
|
||||
src/bun.js/bindings/node/crypto/CryptoKeys.cpp
|
||||
src/bun.js/bindings/node/crypto/CryptoPrimes.cpp
|
||||
src/bun.js/bindings/node/crypto/CryptoSignJob.cpp
|
||||
src/bun.js/bindings/node/crypto/CryptoUtil.cpp
|
||||
src/bun.js/bindings/node/crypto/JSCipher.cpp
|
||||
src/bun.js/bindings/node/crypto/JSCipherConstructor.cpp
|
||||
src/bun.js/bindings/node/crypto/JSCipherPrototype.cpp
|
||||
src/bun.js/bindings/node/crypto/JSDiffieHellman.cpp
|
||||
src/bun.js/bindings/node/crypto/JSDiffieHellmanConstructor.cpp
|
||||
src/bun.js/bindings/node/crypto/JSDiffieHellmanGroup.cpp
|
||||
src/bun.js/bindings/node/crypto/JSDiffieHellmanGroupConstructor.cpp
|
||||
src/bun.js/bindings/node/crypto/JSDiffieHellmanGroupPrototype.cpp
|
||||
src/bun.js/bindings/node/crypto/JSDiffieHellmanPrototype.cpp
|
||||
src/bun.js/bindings/node/crypto/JSECDH.cpp
|
||||
src/bun.js/bindings/node/crypto/JSECDHConstructor.cpp
|
||||
src/bun.js/bindings/node/crypto/JSECDHPrototype.cpp
|
||||
src/bun.js/bindings/node/crypto/JSHash.cpp
|
||||
src/bun.js/bindings/node/crypto/JSHmac.cpp
|
||||
src/bun.js/bindings/node/crypto/JSKeyObject.cpp
|
||||
src/bun.js/bindings/node/crypto/JSKeyObjectConstructor.cpp
|
||||
src/bun.js/bindings/node/crypto/JSKeyObjectPrototype.cpp
|
||||
src/bun.js/bindings/node/crypto/JSPrivateKeyObject.cpp
|
||||
src/bun.js/bindings/node/crypto/JSPrivateKeyObjectConstructor.cpp
|
||||
src/bun.js/bindings/node/crypto/JSPrivateKeyObjectPrototype.cpp
|
||||
src/bun.js/bindings/node/crypto/JSPublicKeyObject.cpp
|
||||
src/bun.js/bindings/node/crypto/JSPublicKeyObjectConstructor.cpp
|
||||
src/bun.js/bindings/node/crypto/JSPublicKeyObjectPrototype.cpp
|
||||
src/bun.js/bindings/node/crypto/JSSecretKeyObject.cpp
|
||||
src/bun.js/bindings/node/crypto/JSSecretKeyObjectConstructor.cpp
|
||||
src/bun.js/bindings/node/crypto/JSSecretKeyObjectPrototype.cpp
|
||||
src/bun.js/bindings/node/crypto/JSSign.cpp
|
||||
src/bun.js/bindings/node/crypto/JSVerify.cpp
|
||||
src/bun.js/bindings/node/crypto/KeyObject.cpp
|
||||
src/bun.js/bindings/node/crypto/node_crypto_binding.cpp
|
||||
src/bun.js/bindings/node/http/JSConnectionsList.cpp
|
||||
src/bun.js/bindings/node/http/JSConnectionsListConstructor.cpp
|
||||
src/bun.js/bindings/node/http/JSConnectionsListPrototype.cpp
|
||||
src/bun.js/bindings/node/http/JSHTTPParser.cpp
|
||||
src/bun.js/bindings/node/http/JSHTTPParserConstructor.cpp
|
||||
src/bun.js/bindings/node/http/JSHTTPParserPrototype.cpp
|
||||
src/bun.js/bindings/node/http/NodeHTTPParser.cpp
|
||||
src/bun.js/bindings/node/NodeTimers.cpp
|
||||
src/bun.js/bindings/NodeAsyncHooks.cpp
|
||||
src/bun.js/bindings/NodeDirent.cpp
|
||||
src/bun.js/bindings/NodeFetch.cpp
|
||||
src/bun.js/bindings/NodeFSStatBinding.cpp
|
||||
src/bun.js/bindings/NodeFSStatFSBinding.cpp
|
||||
src/bun.js/bindings/NodeHTTP.cpp
|
||||
src/bun.js/bindings/NodeTimerObject.cpp
|
||||
src/bun.js/bindings/NodeTLS.cpp
|
||||
src/bun.js/bindings/NodeURL.cpp
|
||||
src/bun.js/bindings/NodeValidator.cpp
|
||||
src/bun.js/bindings/NodeVM.cpp
|
||||
src/bun.js/bindings/NodeVMModule.cpp
|
||||
src/bun.js/bindings/NodeVMScript.cpp
|
||||
src/bun.js/bindings/NodeVMSourceTextModule.cpp
|
||||
src/bun.js/bindings/NodeVMSyntheticModule.cpp
|
||||
src/bun.js/bindings/NoOpForTesting.cpp
|
||||
src/bun.js/bindings/ObjectBindings.cpp
|
||||
src/bun.js/bindings/objects.cpp
|
||||
src/bun.js/bindings/OsBinding.cpp
|
||||
src/bun.js/bindings/Path.cpp
|
||||
src/bun.js/bindings/ProcessBindingBuffer.cpp
|
||||
src/bun.js/bindings/ProcessBindingConstants.cpp
|
||||
src/bun.js/bindings/ProcessBindingFs.cpp
|
||||
src/bun.js/bindings/ProcessBindingHTTPParser.cpp
|
||||
src/bun.js/bindings/ProcessBindingNatives.cpp
|
||||
src/bun.js/bindings/ProcessBindingTTYWrap.cpp
|
||||
src/bun.js/bindings/ProcessBindingUV.cpp
|
||||
src/bun.js/bindings/ProcessIdentifier.cpp
|
||||
src/bun.js/bindings/RegularExpression.cpp
|
||||
src/bun.js/bindings/S3Error.cpp
|
||||
src/bun.js/bindings/ScriptExecutionContext.cpp
|
||||
src/bun.js/bindings/Serialization.cpp
|
||||
src/bun.js/bindings/ServerRouteList.cpp
|
||||
src/bun.js/bindings/spawn.cpp
|
||||
src/bun.js/bindings/SQLClient.cpp
|
||||
src/bun.js/bindings/sqlite/JSSQLStatement.cpp
|
||||
src/bun.js/bindings/stripANSI.cpp
|
||||
src/bun.js/bindings/Strong.cpp
|
||||
src/bun.js/bindings/TextCodec.cpp
|
||||
src/bun.js/bindings/TextCodecCJK.cpp
|
||||
src/bun.js/bindings/TextCodecReplacement.cpp
|
||||
src/bun.js/bindings/TextCodecSingleByte.cpp
|
||||
src/bun.js/bindings/TextCodecUserDefined.cpp
|
||||
src/bun.js/bindings/TextCodecWrapper.cpp
|
||||
src/bun.js/bindings/TextEncoding.cpp
|
||||
src/bun.js/bindings/TextEncodingRegistry.cpp
|
||||
src/bun.js/bindings/Uint8Array.cpp
|
||||
src/bun.js/bindings/Undici.cpp
|
||||
src/bun.js/bindings/URLDecomposition.cpp
|
||||
src/bun.js/bindings/URLSearchParams.cpp
|
||||
src/bun.js/bindings/UtilInspect.cpp
|
||||
src/bun.js/bindings/v8/node.cpp
|
||||
src/bun.js/bindings/v8/shim/Function.cpp
|
||||
src/bun.js/bindings/v8/shim/FunctionTemplate.cpp
|
||||
src/bun.js/bindings/v8/shim/GlobalInternals.cpp
|
||||
src/bun.js/bindings/v8/shim/Handle.cpp
|
||||
src/bun.js/bindings/v8/shim/HandleScopeBuffer.cpp
|
||||
src/bun.js/bindings/v8/shim/InternalFieldObject.cpp
|
||||
src/bun.js/bindings/v8/shim/Map.cpp
|
||||
src/bun.js/bindings/v8/shim/ObjectTemplate.cpp
|
||||
src/bun.js/bindings/v8/shim/Oddball.cpp
|
||||
src/bun.js/bindings/v8/shim/TaggedPointer.cpp
|
||||
src/bun.js/bindings/v8/v8_api_internal.cpp
|
||||
src/bun.js/bindings/v8/v8_internal.cpp
|
||||
src/bun.js/bindings/v8/V8Array.cpp
|
||||
src/bun.js/bindings/v8/V8Boolean.cpp
|
||||
src/bun.js/bindings/v8/V8Context.cpp
|
||||
src/bun.js/bindings/v8/V8EscapableHandleScope.cpp
|
||||
src/bun.js/bindings/v8/V8EscapableHandleScopeBase.cpp
|
||||
src/bun.js/bindings/v8/V8External.cpp
|
||||
src/bun.js/bindings/v8/V8Function.cpp
|
||||
src/bun.js/bindings/v8/V8FunctionCallbackInfo.cpp
|
||||
src/bun.js/bindings/v8/V8FunctionTemplate.cpp
|
||||
src/bun.js/bindings/v8/V8HandleScope.cpp
|
||||
src/bun.js/bindings/v8/V8Isolate.cpp
|
||||
src/bun.js/bindings/v8/V8Local.cpp
|
||||
src/bun.js/bindings/v8/V8Maybe.cpp
|
||||
src/bun.js/bindings/v8/V8Number.cpp
|
||||
src/bun.js/bindings/v8/V8Object.cpp
|
||||
src/bun.js/bindings/v8/V8ObjectTemplate.cpp
|
||||
src/bun.js/bindings/v8/V8String.cpp
|
||||
src/bun.js/bindings/v8/V8Template.cpp
|
||||
src/bun.js/bindings/v8/V8Value.cpp
|
||||
src/bun.js/bindings/Weak.cpp
|
||||
src/bun.js/bindings/webcore/AbortController.cpp
|
||||
src/bun.js/bindings/webcore/AbortSignal.cpp
|
||||
src/bun.js/bindings/webcore/ActiveDOMObject.cpp
|
||||
src/bun.js/bindings/webcore/BroadcastChannel.cpp
|
||||
src/bun.js/bindings/webcore/BunBroadcastChannelRegistry.cpp
|
||||
src/bun.js/bindings/webcore/CloseEvent.cpp
|
||||
src/bun.js/bindings/webcore/CommonAtomStrings.cpp
|
||||
src/bun.js/bindings/webcore/ContextDestructionObserver.cpp
|
||||
src/bun.js/bindings/webcore/CustomEvent.cpp
|
||||
src/bun.js/bindings/webcore/CustomEventCustom.cpp
|
||||
src/bun.js/bindings/webcore/DOMJITHelpers.cpp
|
||||
src/bun.js/bindings/webcore/ErrorCallback.cpp
|
||||
src/bun.js/bindings/webcore/ErrorEvent.cpp
|
||||
src/bun.js/bindings/webcore/Event.cpp
|
||||
src/bun.js/bindings/webcore/EventContext.cpp
|
||||
src/bun.js/bindings/webcore/EventDispatcher.cpp
|
||||
src/bun.js/bindings/webcore/EventEmitter.cpp
|
||||
src/bun.js/bindings/webcore/EventFactory.cpp
|
||||
src/bun.js/bindings/webcore/EventListenerMap.cpp
|
||||
src/bun.js/bindings/webcore/EventNames.cpp
|
||||
src/bun.js/bindings/webcore/EventPath.cpp
|
||||
src/bun.js/bindings/webcore/EventTarget.cpp
|
||||
src/bun.js/bindings/webcore/EventTargetConcrete.cpp
|
||||
src/bun.js/bindings/webcore/EventTargetFactory.cpp
|
||||
src/bun.js/bindings/webcore/FetchHeaders.cpp
|
||||
src/bun.js/bindings/webcore/HeaderFieldTokenizer.cpp
|
||||
src/bun.js/bindings/webcore/HTTPHeaderField.cpp
|
||||
src/bun.js/bindings/webcore/HTTPHeaderIdentifiers.cpp
|
||||
src/bun.js/bindings/webcore/HTTPHeaderMap.cpp
|
||||
src/bun.js/bindings/webcore/HTTPHeaderNames.cpp
|
||||
src/bun.js/bindings/webcore/HTTPHeaderStrings.cpp
|
||||
src/bun.js/bindings/webcore/HTTPHeaderValues.cpp
|
||||
src/bun.js/bindings/webcore/HTTPParsers.cpp
|
||||
src/bun.js/bindings/webcore/IdentifierEventListenerMap.cpp
|
||||
src/bun.js/bindings/webcore/InternalWritableStream.cpp
|
||||
src/bun.js/bindings/webcore/JSAbortAlgorithm.cpp
|
||||
src/bun.js/bindings/webcore/JSAbortController.cpp
|
||||
src/bun.js/bindings/webcore/JSAbortSignal.cpp
|
||||
src/bun.js/bindings/webcore/JSAbortSignalCustom.cpp
|
||||
src/bun.js/bindings/webcore/JSAddEventListenerOptions.cpp
|
||||
src/bun.js/bindings/webcore/JSBroadcastChannel.cpp
|
||||
src/bun.js/bindings/webcore/JSByteLengthQueuingStrategy.cpp
|
||||
src/bun.js/bindings/webcore/JSCallbackData.cpp
|
||||
src/bun.js/bindings/webcore/JSCloseEvent.cpp
|
||||
src/bun.js/bindings/webcore/JSCookie.cpp
|
||||
src/bun.js/bindings/webcore/JSCookieMap.cpp
|
||||
src/bun.js/bindings/webcore/JSCountQueuingStrategy.cpp
|
||||
src/bun.js/bindings/webcore/JSCustomEvent.cpp
|
||||
src/bun.js/bindings/webcore/JSDOMBindingInternalsBuiltins.cpp
|
||||
src/bun.js/bindings/webcore/JSDOMBuiltinConstructorBase.cpp
|
||||
src/bun.js/bindings/webcore/JSDOMConstructorBase.cpp
|
||||
src/bun.js/bindings/webcore/JSDOMConvertDate.cpp
|
||||
src/bun.js/bindings/webcore/JSDOMConvertNumbers.cpp
|
||||
src/bun.js/bindings/webcore/JSDOMConvertStrings.cpp
|
||||
src/bun.js/bindings/webcore/JSDOMConvertWebGL.cpp
|
||||
src/bun.js/bindings/webcore/JSDOMException.cpp
|
||||
src/bun.js/bindings/webcore/JSDOMFormData.cpp
|
||||
src/bun.js/bindings/webcore/JSDOMGuardedObject.cpp
|
||||
src/bun.js/bindings/webcore/JSDOMIterator.cpp
|
||||
src/bun.js/bindings/webcore/JSDOMOperation.cpp
|
||||
src/bun.js/bindings/webcore/JSDOMPromise.cpp
|
||||
src/bun.js/bindings/webcore/JSDOMPromiseDeferred.cpp
|
||||
src/bun.js/bindings/webcore/JSDOMURL.cpp
|
||||
src/bun.js/bindings/webcore/JSErrorCallback.cpp
|
||||
src/bun.js/bindings/webcore/JSErrorEvent.cpp
|
||||
src/bun.js/bindings/webcore/JSErrorEventCustom.cpp
|
||||
src/bun.js/bindings/webcore/JSErrorHandler.cpp
|
||||
src/bun.js/bindings/webcore/JSEvent.cpp
|
||||
src/bun.js/bindings/webcore/JSEventCustom.cpp
|
||||
src/bun.js/bindings/webcore/JSEventDOMJIT.cpp
|
||||
src/bun.js/bindings/webcore/JSEventEmitter.cpp
|
||||
src/bun.js/bindings/webcore/JSEventEmitterCustom.cpp
|
||||
src/bun.js/bindings/webcore/JSEventInit.cpp
|
||||
src/bun.js/bindings/webcore/JSEventListener.cpp
|
||||
src/bun.js/bindings/webcore/JSEventListenerOptions.cpp
|
||||
src/bun.js/bindings/webcore/JSEventModifierInit.cpp
|
||||
src/bun.js/bindings/webcore/JSEventTarget.cpp
|
||||
src/bun.js/bindings/webcore/JSEventTargetCustom.cpp
|
||||
src/bun.js/bindings/webcore/JSEventTargetNode.cpp
|
||||
src/bun.js/bindings/webcore/JSFetchHeaders.cpp
|
||||
src/bun.js/bindings/webcore/JSMessageChannel.cpp
|
||||
src/bun.js/bindings/webcore/JSMessageChannelCustom.cpp
|
||||
src/bun.js/bindings/webcore/JSMessageEvent.cpp
|
||||
src/bun.js/bindings/webcore/JSMessageEventCustom.cpp
|
||||
src/bun.js/bindings/webcore/JSMessagePort.cpp
|
||||
src/bun.js/bindings/webcore/JSMessagePortCustom.cpp
|
||||
src/bun.js/bindings/webcore/JSMIMEBindings.cpp
|
||||
src/bun.js/bindings/webcore/JSMIMEParams.cpp
|
||||
src/bun.js/bindings/webcore/JSMIMEType.cpp
|
||||
src/bun.js/bindings/webcore/JSPerformance.cpp
|
||||
src/bun.js/bindings/webcore/JSPerformanceEntry.cpp
|
||||
src/bun.js/bindings/webcore/JSPerformanceEntryCustom.cpp
|
||||
src/bun.js/bindings/webcore/JSPerformanceMark.cpp
|
||||
src/bun.js/bindings/webcore/JSPerformanceMarkOptions.cpp
|
||||
src/bun.js/bindings/webcore/JSPerformanceMeasure.cpp
|
||||
src/bun.js/bindings/webcore/JSPerformanceMeasureOptions.cpp
|
||||
src/bun.js/bindings/webcore/JSPerformanceObserver.cpp
|
||||
src/bun.js/bindings/webcore/JSPerformanceObserverCallback.cpp
|
||||
src/bun.js/bindings/webcore/JSPerformanceObserverCustom.cpp
|
||||
src/bun.js/bindings/webcore/JSPerformanceObserverEntryList.cpp
|
||||
src/bun.js/bindings/webcore/JSPerformanceResourceTiming.cpp
|
||||
src/bun.js/bindings/webcore/JSPerformanceServerTiming.cpp
|
||||
src/bun.js/bindings/webcore/JSPerformanceTiming.cpp
|
||||
src/bun.js/bindings/webcore/JSReadableByteStreamController.cpp
|
||||
src/bun.js/bindings/webcore/JSReadableStream.cpp
|
||||
src/bun.js/bindings/webcore/JSReadableStreamBYOBReader.cpp
|
||||
src/bun.js/bindings/webcore/JSReadableStreamBYOBRequest.cpp
|
||||
src/bun.js/bindings/webcore/JSReadableStreamDefaultController.cpp
|
||||
src/bun.js/bindings/webcore/JSReadableStreamDefaultReader.cpp
|
||||
src/bun.js/bindings/webcore/JSReadableStreamSink.cpp
|
||||
src/bun.js/bindings/webcore/JSReadableStreamSource.cpp
|
||||
src/bun.js/bindings/webcore/JSReadableStreamSourceCustom.cpp
|
||||
src/bun.js/bindings/webcore/JSStructuredSerializeOptions.cpp
|
||||
src/bun.js/bindings/webcore/JSTextDecoderStream.cpp
|
||||
src/bun.js/bindings/webcore/JSTextEncoder.cpp
|
||||
src/bun.js/bindings/webcore/JSTextEncoderStream.cpp
|
||||
src/bun.js/bindings/webcore/JSTransformStream.cpp
|
||||
src/bun.js/bindings/webcore/JSTransformStreamDefaultController.cpp
|
||||
src/bun.js/bindings/webcore/JSURLSearchParams.cpp
|
||||
src/bun.js/bindings/webcore/JSWasmStreamingCompiler.cpp
|
||||
src/bun.js/bindings/webcore/JSWebSocket.cpp
|
||||
src/bun.js/bindings/webcore/JSWorker.cpp
|
||||
src/bun.js/bindings/webcore/JSWorkerOptions.cpp
|
||||
src/bun.js/bindings/webcore/JSWritableStream.cpp
|
||||
src/bun.js/bindings/webcore/JSWritableStreamDefaultController.cpp
|
||||
src/bun.js/bindings/webcore/JSWritableStreamDefaultWriter.cpp
|
||||
src/bun.js/bindings/webcore/JSWritableStreamSink.cpp
|
||||
src/bun.js/bindings/webcore/MessageChannel.cpp
|
||||
src/bun.js/bindings/webcore/MessageEvent.cpp
|
||||
src/bun.js/bindings/webcore/MessagePort.cpp
|
||||
src/bun.js/bindings/webcore/MessagePortChannel.cpp
|
||||
src/bun.js/bindings/webcore/MessagePortChannelProvider.cpp
|
||||
src/bun.js/bindings/webcore/MessagePortChannelProviderImpl.cpp
|
||||
src/bun.js/bindings/webcore/MessagePortChannelRegistry.cpp
|
||||
src/bun.js/bindings/webcore/NetworkLoadMetrics.cpp
|
||||
src/bun.js/bindings/webcore/Performance.cpp
|
||||
src/bun.js/bindings/webcore/PerformanceEntry.cpp
|
||||
src/bun.js/bindings/webcore/PerformanceMark.cpp
|
||||
src/bun.js/bindings/webcore/PerformanceMeasure.cpp
|
||||
src/bun.js/bindings/webcore/PerformanceObserver.cpp
|
||||
src/bun.js/bindings/webcore/PerformanceObserverEntryList.cpp
|
||||
src/bun.js/bindings/webcore/PerformanceResourceTiming.cpp
|
||||
src/bun.js/bindings/webcore/PerformanceServerTiming.cpp
|
||||
src/bun.js/bindings/webcore/PerformanceTiming.cpp
|
||||
src/bun.js/bindings/webcore/PerformanceUserTiming.cpp
|
||||
src/bun.js/bindings/webcore/ReadableStream.cpp
|
||||
src/bun.js/bindings/webcore/ReadableStreamDefaultController.cpp
|
||||
src/bun.js/bindings/webcore/ReadableStreamSink.cpp
|
||||
src/bun.js/bindings/webcore/ReadableStreamSource.cpp
|
||||
src/bun.js/bindings/webcore/ResourceTiming.cpp
|
||||
src/bun.js/bindings/webcore/RFC7230.cpp
|
||||
src/bun.js/bindings/webcore/SerializedScriptValue.cpp
|
||||
src/bun.js/bindings/webcore/ServerTiming.cpp
|
||||
src/bun.js/bindings/webcore/ServerTimingParser.cpp
|
||||
src/bun.js/bindings/webcore/StructuredClone.cpp
|
||||
src/bun.js/bindings/webcore/TextEncoder.cpp
|
||||
src/bun.js/bindings/webcore/WebCoreTypedArrayController.cpp
|
||||
src/bun.js/bindings/webcore/WebSocket.cpp
|
||||
src/bun.js/bindings/webcore/Worker.cpp
|
||||
src/bun.js/bindings/webcore/WritableStream.cpp
|
||||
src/bun.js/bindings/webcrypto/CommonCryptoDERUtilities.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithm.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmAES_CBC.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmAES_CBCOpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmAES_CFB.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmAES_CFBOpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmAES_CTR.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmAES_CTROpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmAES_GCM.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmAES_GCMOpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmAES_KW.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmAES_KWOpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmECDH.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmECDHOpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmECDSA.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmECDSAOpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmEd25519.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmHKDF.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmHKDFOpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmHMAC.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmHMACOpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmPBKDF2.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmPBKDF2OpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmRegistry.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmRegistryOpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmRSA_OAEP.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmRSA_OAEPOpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmRSA_PSS.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmRSA_PSSOpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmRSAES_PKCS1_v1_5.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmRSAES_PKCS1_v1_5OpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmRSASSA_PKCS1_v1_5.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmRSASSA_PKCS1_v1_5OpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA1.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA224.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA256.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA384.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmSHA512.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoAlgorithmX25519.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoDigest.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoKey.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoKeyAES.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoKeyEC.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoKeyECOpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoKeyHMAC.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoKeyOKP.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoKeyOKPOpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoKeyRaw.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoKeyRSA.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoKeyRSAComponents.cpp
|
||||
src/bun.js/bindings/webcrypto/CryptoKeyRSAOpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/JSAesCbcCfbParams.cpp
|
||||
src/bun.js/bindings/webcrypto/JSAesCtrParams.cpp
|
||||
src/bun.js/bindings/webcrypto/JSAesGcmParams.cpp
|
||||
src/bun.js/bindings/webcrypto/JSAesKeyParams.cpp
|
||||
src/bun.js/bindings/webcrypto/JSCryptoAesKeyAlgorithm.cpp
|
||||
src/bun.js/bindings/webcrypto/JSCryptoAlgorithmParameters.cpp
|
||||
src/bun.js/bindings/webcrypto/JSCryptoEcKeyAlgorithm.cpp
|
||||
src/bun.js/bindings/webcrypto/JSCryptoHmacKeyAlgorithm.cpp
|
||||
src/bun.js/bindings/webcrypto/JSCryptoKey.cpp
|
||||
src/bun.js/bindings/webcrypto/JSCryptoKeyAlgorithm.cpp
|
||||
src/bun.js/bindings/webcrypto/JSCryptoKeyPair.cpp
|
||||
src/bun.js/bindings/webcrypto/JSCryptoKeyUsage.cpp
|
||||
src/bun.js/bindings/webcrypto/JSCryptoRsaHashedKeyAlgorithm.cpp
|
||||
src/bun.js/bindings/webcrypto/JSCryptoRsaKeyAlgorithm.cpp
|
||||
src/bun.js/bindings/webcrypto/JSEcdhKeyDeriveParams.cpp
|
||||
src/bun.js/bindings/webcrypto/JSEcdsaParams.cpp
|
||||
src/bun.js/bindings/webcrypto/JSEcKeyParams.cpp
|
||||
src/bun.js/bindings/webcrypto/JSHkdfParams.cpp
|
||||
src/bun.js/bindings/webcrypto/JSHmacKeyParams.cpp
|
||||
src/bun.js/bindings/webcrypto/JSJsonWebKey.cpp
|
||||
src/bun.js/bindings/webcrypto/JSPbkdf2Params.cpp
|
||||
src/bun.js/bindings/webcrypto/JSRsaHashedImportParams.cpp
|
||||
src/bun.js/bindings/webcrypto/JSRsaHashedKeyGenParams.cpp
|
||||
src/bun.js/bindings/webcrypto/JSRsaKeyGenParams.cpp
|
||||
src/bun.js/bindings/webcrypto/JSRsaOaepParams.cpp
|
||||
src/bun.js/bindings/webcrypto/JSRsaOtherPrimesInfo.cpp
|
||||
src/bun.js/bindings/webcrypto/JSRsaPssParams.cpp
|
||||
src/bun.js/bindings/webcrypto/JSSubtleCrypto.cpp
|
||||
src/bun.js/bindings/webcrypto/JSX25519Params.cpp
|
||||
src/bun.js/bindings/webcrypto/OpenSSLUtilities.cpp
|
||||
src/bun.js/bindings/webcrypto/PhonyWorkQueue.cpp
|
||||
src/bun.js/bindings/webcrypto/SerializedCryptoKeyWrapOpenSSL.cpp
|
||||
src/bun.js/bindings/webcrypto/SubtleCrypto.cpp
|
||||
src/bun.js/bindings/workaround-missing-symbols.cpp
|
||||
src/bun.js/bindings/wtf-bindings.cpp
|
||||
src/bun.js/bindings/ZigGeneratedCode.cpp
|
||||
src/bun.js/bindings/ZigGlobalObject.cpp
|
||||
src/bun.js/bindings/ZigSourceProvider.cpp
|
||||
src/bun.js/modules/NodeModuleModule.cpp
|
||||
src/bun.js/modules/NodeTTYModule.cpp
|
||||
src/bun.js/modules/NodeUtilTypesModule.cpp
|
||||
src/bun.js/modules/ObjectModule.cpp
|
||||
src/deps/libuwsockets.cpp
|
||||
src/io/io_darwin.cpp
|
||||
src/vm/Semaphore.cpp
|
||||
src/vm/SigintWatcher.cpp
|
||||
21
cmake/sources/JavaScriptCodegenSources.txt
Normal file
21
cmake/sources/JavaScriptCodegenSources.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
src/codegen/bake-codegen.ts
|
||||
src/codegen/bindgen-lib-internal.ts
|
||||
src/codegen/bindgen-lib.ts
|
||||
src/codegen/bindgen.ts
|
||||
src/codegen/buildTypeFlag.ts
|
||||
src/codegen/builtin-parser.ts
|
||||
src/codegen/bundle-functions.ts
|
||||
src/codegen/bundle-modules.ts
|
||||
src/codegen/class-definitions.ts
|
||||
src/codegen/client-js.ts
|
||||
src/codegen/cppbind.ts
|
||||
src/codegen/create-hash-table.ts
|
||||
src/codegen/generate-classes.ts
|
||||
src/codegen/generate-compact-string-table.ts
|
||||
src/codegen/generate-js2native.ts
|
||||
src/codegen/generate-jssink.ts
|
||||
src/codegen/generate-node-errors.ts
|
||||
src/codegen/helpers.ts
|
||||
src/codegen/internal-module-registry-scanner.ts
|
||||
src/codegen/replacements.ts
|
||||
src/codegen/shared-types.ts
|
||||
171
cmake/sources/JavaScriptSources.txt
Normal file
171
cmake/sources/JavaScriptSources.txt
Normal file
@@ -0,0 +1,171 @@
|
||||
src/js/builtins.d.ts
|
||||
src/js/builtins/Bake.ts
|
||||
src/js/builtins/BundlerPlugin.ts
|
||||
src/js/builtins/ByteLengthQueuingStrategy.ts
|
||||
src/js/builtins/CommonJS.ts
|
||||
src/js/builtins/ConsoleObject.ts
|
||||
src/js/builtins/CountQueuingStrategy.ts
|
||||
src/js/builtins/Glob.ts
|
||||
src/js/builtins/ImportMetaObject.ts
|
||||
src/js/builtins/Ipc.ts
|
||||
src/js/builtins/JSBufferConstructor.ts
|
||||
src/js/builtins/JSBufferPrototype.ts
|
||||
src/js/builtins/NodeModuleObject.ts
|
||||
src/js/builtins/Peek.ts
|
||||
src/js/builtins/ProcessObjectInternals.ts
|
||||
src/js/builtins/ReadableByteStreamController.ts
|
||||
src/js/builtins/ReadableByteStreamInternals.ts
|
||||
src/js/builtins/ReadableStream.ts
|
||||
src/js/builtins/ReadableStreamBYOBReader.ts
|
||||
src/js/builtins/ReadableStreamBYOBRequest.ts
|
||||
src/js/builtins/ReadableStreamDefaultController.ts
|
||||
src/js/builtins/ReadableStreamDefaultReader.ts
|
||||
src/js/builtins/ReadableStreamInternals.ts
|
||||
src/js/builtins/shell.ts
|
||||
src/js/builtins/StreamInternals.ts
|
||||
src/js/builtins/TextDecoderStream.ts
|
||||
src/js/builtins/TextEncoderStream.ts
|
||||
src/js/builtins/TransformStream.ts
|
||||
src/js/builtins/TransformStreamDefaultController.ts
|
||||
src/js/builtins/TransformStreamInternals.ts
|
||||
src/js/builtins/UtilInspect.ts
|
||||
src/js/builtins/WasmStreaming.ts
|
||||
src/js/builtins/WritableStreamDefaultController.ts
|
||||
src/js/builtins/WritableStreamDefaultWriter.ts
|
||||
src/js/builtins/WritableStreamInternals.ts
|
||||
src/js/bun/ffi.ts
|
||||
src/js/bun/sql.ts
|
||||
src/js/bun/sqlite.ts
|
||||
src/js/internal-for-testing.ts
|
||||
src/js/internal/abort_listener.ts
|
||||
src/js/internal/assert/assertion_error.ts
|
||||
src/js/internal/assert/calltracker.ts
|
||||
src/js/internal/assert/myers_diff.ts
|
||||
src/js/internal/assert/utils.ts
|
||||
src/js/internal/buffer.ts
|
||||
src/js/internal/cluster/child.ts
|
||||
src/js/internal/cluster/isPrimary.ts
|
||||
src/js/internal/cluster/primary.ts
|
||||
src/js/internal/cluster/RoundRobinHandle.ts
|
||||
src/js/internal/cluster/Worker.ts
|
||||
src/js/internal/crypto/x509.ts
|
||||
src/js/internal/debugger.ts
|
||||
src/js/internal/errors.ts
|
||||
src/js/internal/fifo.ts
|
||||
src/js/internal/fixed_queue.ts
|
||||
src/js/internal/freelist.ts
|
||||
src/js/internal/fs/cp-sync.ts
|
||||
src/js/internal/fs/cp.ts
|
||||
src/js/internal/fs/glob.ts
|
||||
src/js/internal/fs/streams.ts
|
||||
src/js/internal/html.ts
|
||||
src/js/internal/http.ts
|
||||
src/js/internal/http/FakeSocket.ts
|
||||
src/js/internal/linkedlist.ts
|
||||
src/js/internal/primordials.js
|
||||
src/js/internal/promisify.ts
|
||||
src/js/internal/shared.ts
|
||||
src/js/internal/sql/errors.ts
|
||||
src/js/internal/sql/postgres.ts
|
||||
src/js/internal/sql/query.ts
|
||||
src/js/internal/sql/shared.ts
|
||||
src/js/internal/sql/sqlite.ts
|
||||
src/js/internal/sql/utils.ts
|
||||
src/js/internal/stream.promises.ts
|
||||
src/js/internal/stream.ts
|
||||
src/js/internal/streams/add-abort-signal.ts
|
||||
src/js/internal/streams/compose.ts
|
||||
src/js/internal/streams/destroy.ts
|
||||
src/js/internal/streams/duplex.ts
|
||||
src/js/internal/streams/duplexify.ts
|
||||
src/js/internal/streams/duplexpair.ts
|
||||
src/js/internal/streams/end-of-stream.ts
|
||||
src/js/internal/streams/from.ts
|
||||
src/js/internal/streams/lazy_transform.ts
|
||||
src/js/internal/streams/legacy.ts
|
||||
src/js/internal/streams/native-readable.ts
|
||||
src/js/internal/streams/operators.ts
|
||||
src/js/internal/streams/passthrough.ts
|
||||
src/js/internal/streams/pipeline.ts
|
||||
src/js/internal/streams/readable.ts
|
||||
src/js/internal/streams/state.ts
|
||||
src/js/internal/streams/transform.ts
|
||||
src/js/internal/streams/utils.ts
|
||||
src/js/internal/streams/writable.ts
|
||||
src/js/internal/timers.ts
|
||||
src/js/internal/tls.ts
|
||||
src/js/internal/tty.ts
|
||||
src/js/internal/url.ts
|
||||
src/js/internal/util/colors.ts
|
||||
src/js/internal/util/inspect.d.ts
|
||||
src/js/internal/util/inspect.js
|
||||
src/js/internal/util/mime.ts
|
||||
src/js/internal/validators.ts
|
||||
src/js/internal/webstreams_adapters.ts
|
||||
src/js/node/_http_agent.ts
|
||||
src/js/node/_http_client.ts
|
||||
src/js/node/_http_common.ts
|
||||
src/js/node/_http_incoming.ts
|
||||
src/js/node/_http_outgoing.ts
|
||||
src/js/node/_http_server.ts
|
||||
src/js/node/_stream_duplex.ts
|
||||
src/js/node/_stream_passthrough.ts
|
||||
src/js/node/_stream_readable.ts
|
||||
src/js/node/_stream_transform.ts
|
||||
src/js/node/_stream_wrap.ts
|
||||
src/js/node/_stream_writable.ts
|
||||
src/js/node/_tls_common.ts
|
||||
src/js/node/assert.strict.ts
|
||||
src/js/node/assert.ts
|
||||
src/js/node/async_hooks.ts
|
||||
src/js/node/child_process.ts
|
||||
src/js/node/cluster.ts
|
||||
src/js/node/console.ts
|
||||
src/js/node/crypto.ts
|
||||
src/js/node/dgram.ts
|
||||
src/js/node/diagnostics_channel.ts
|
||||
src/js/node/dns.promises.ts
|
||||
src/js/node/dns.ts
|
||||
src/js/node/domain.ts
|
||||
src/js/node/events.ts
|
||||
src/js/node/fs.promises.ts
|
||||
src/js/node/fs.ts
|
||||
src/js/node/http.ts
|
||||
src/js/node/http2.ts
|
||||
src/js/node/https.ts
|
||||
src/js/node/inspector.ts
|
||||
src/js/node/net.ts
|
||||
src/js/node/os.ts
|
||||
src/js/node/path.posix.ts
|
||||
src/js/node/path.ts
|
||||
src/js/node/path.win32.ts
|
||||
src/js/node/perf_hooks.ts
|
||||
src/js/node/punycode.ts
|
||||
src/js/node/querystring.ts
|
||||
src/js/node/readline.promises.ts
|
||||
src/js/node/readline.ts
|
||||
src/js/node/repl.ts
|
||||
src/js/node/stream.consumers.ts
|
||||
src/js/node/stream.promises.ts
|
||||
src/js/node/stream.ts
|
||||
src/js/node/stream.web.ts
|
||||
src/js/node/test.ts
|
||||
src/js/node/timers.promises.ts
|
||||
src/js/node/timers.ts
|
||||
src/js/node/tls.ts
|
||||
src/js/node/trace_events.ts
|
||||
src/js/node/tty.ts
|
||||
src/js/node/url.ts
|
||||
src/js/node/util.ts
|
||||
src/js/node/v8.ts
|
||||
src/js/node/vm.ts
|
||||
src/js/node/wasi.ts
|
||||
src/js/node/worker_threads.ts
|
||||
src/js/node/zlib.ts
|
||||
src/js/private.d.ts
|
||||
src/js/thirdparty/isomorphic-fetch.ts
|
||||
src/js/thirdparty/node-fetch.ts
|
||||
src/js/thirdparty/undici.js
|
||||
src/js/thirdparty/vercel_fetch.js
|
||||
src/js/thirdparty/ws.js
|
||||
src/js/wasi-runner.js
|
||||
24
cmake/sources/NodeFallbacksSources.txt
Normal file
24
cmake/sources/NodeFallbacksSources.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
src/node-fallbacks/assert.js
|
||||
src/node-fallbacks/buffer.js
|
||||
src/node-fallbacks/console.js
|
||||
src/node-fallbacks/constants.js
|
||||
src/node-fallbacks/crypto.js
|
||||
src/node-fallbacks/domain.js
|
||||
src/node-fallbacks/events.js
|
||||
src/node-fallbacks/http.js
|
||||
src/node-fallbacks/https.js
|
||||
src/node-fallbacks/net.js
|
||||
src/node-fallbacks/os.js
|
||||
src/node-fallbacks/path.js
|
||||
src/node-fallbacks/process.js
|
||||
src/node-fallbacks/punycode.js
|
||||
src/node-fallbacks/querystring.js
|
||||
src/node-fallbacks/stream.js
|
||||
src/node-fallbacks/string_decoder.js
|
||||
src/node-fallbacks/sys.js
|
||||
src/node-fallbacks/timers.js
|
||||
src/node-fallbacks/timers.promises.js
|
||||
src/node-fallbacks/tty.js
|
||||
src/node-fallbacks/url.js
|
||||
src/node-fallbacks/util.js
|
||||
src/node-fallbacks/zlib.js
|
||||
25
cmake/sources/ZigGeneratedClassesSources.txt
Normal file
25
cmake/sources/ZigGeneratedClassesSources.txt
Normal file
@@ -0,0 +1,25 @@
|
||||
src/bun.js/api/BunObject.classes.ts
|
||||
src/bun.js/api/crypto.classes.ts
|
||||
src/bun.js/api/ffi.classes.ts
|
||||
src/bun.js/api/filesystem_router.classes.ts
|
||||
src/bun.js/api/Glob.classes.ts
|
||||
src/bun.js/api/h2.classes.ts
|
||||
src/bun.js/api/html_rewriter.classes.ts
|
||||
src/bun.js/api/JSBundler.classes.ts
|
||||
src/bun.js/api/postgres.classes.ts
|
||||
src/bun.js/api/ResumableSink.classes.ts
|
||||
src/bun.js/api/S3Client.classes.ts
|
||||
src/bun.js/api/S3Stat.classes.ts
|
||||
src/bun.js/api/server.classes.ts
|
||||
src/bun.js/api/Shell.classes.ts
|
||||
src/bun.js/api/ShellArgs.classes.ts
|
||||
src/bun.js/api/sockets.classes.ts
|
||||
src/bun.js/api/sourcemap.classes.ts
|
||||
src/bun.js/api/streams.classes.ts
|
||||
src/bun.js/api/valkey.classes.ts
|
||||
src/bun.js/api/zlib.classes.ts
|
||||
src/bun.js/node/node.classes.ts
|
||||
src/bun.js/resolve_message.classes.ts
|
||||
src/bun.js/test/jest.classes.ts
|
||||
src/bun.js/webcore/encoding.classes.ts
|
||||
src/bun.js/webcore/response.classes.ts
|
||||
1016
cmake/sources/ZigSources.txt
Normal file
1016
cmake/sources/ZigSources.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@ register_repository(
|
||||
REPOSITORY
|
||||
oven-sh/boringssl
|
||||
COMMIT
|
||||
f1ffd9e83d4f5c28a9c70d73f9a4e6fcf310062f
|
||||
7a5d984c69b0c34c4cbb56c6812eaa5b9bef485c
|
||||
)
|
||||
|
||||
register_cmake_command(
|
||||
|
||||
@@ -2,8 +2,6 @@ include(PathUtils)
|
||||
|
||||
if(DEBUG)
|
||||
set(bun bun-debug)
|
||||
elseif(ENABLE_ASAN AND ENABLE_VALGRIND)
|
||||
set(bun bun-asan-valgrind)
|
||||
elseif(ENABLE_ASAN)
|
||||
set(bun bun-asan)
|
||||
elseif(ENABLE_VALGRIND)
|
||||
@@ -621,7 +619,6 @@ register_command(
|
||||
-Dcpu=${ZIG_CPU}
|
||||
-Denable_logs=$<IF:$<BOOL:${ENABLE_LOGS}>,true,false>
|
||||
-Denable_asan=$<IF:$<BOOL:${ENABLE_ZIG_ASAN}>,true,false>
|
||||
-Denable_valgrind=$<IF:$<BOOL:${ENABLE_VALGRIND}>,true,false>
|
||||
-Dversion=${VERSION}
|
||||
-Dreported_nodejs_version=${NODEJS_VERSION}
|
||||
-Dcanary=${CANARY_REVISION}
|
||||
@@ -639,7 +636,6 @@ register_command(
|
||||
SOURCES
|
||||
${BUN_ZIG_SOURCES}
|
||||
${BUN_ZIG_GENERATED_SOURCES}
|
||||
${CWD}/src/install/PackageManager/scanner-entry.ts # Is there a better way to do this?
|
||||
)
|
||||
|
||||
set_property(TARGET bun-zig PROPERTY JOB_POOL compile_pool)
|
||||
@@ -889,8 +885,12 @@ if(NOT WIN32)
|
||||
endif()
|
||||
|
||||
if(ENABLE_ASAN)
|
||||
target_compile_options(${bun} PUBLIC -fsanitize=address)
|
||||
target_link_libraries(${bun} PUBLIC -fsanitize=address)
|
||||
target_compile_options(${bun} PUBLIC
|
||||
-fsanitize=address
|
||||
)
|
||||
target_link_libraries(${bun} PUBLIC
|
||||
-fsanitize=address
|
||||
)
|
||||
endif()
|
||||
|
||||
target_compile_options(${bun} PUBLIC
|
||||
@@ -929,8 +929,12 @@ if(NOT WIN32)
|
||||
)
|
||||
|
||||
if(ENABLE_ASAN)
|
||||
target_compile_options(${bun} PUBLIC -fsanitize=address)
|
||||
target_link_libraries(${bun} PUBLIC -fsanitize=address)
|
||||
target_compile_options(${bun} PUBLIC
|
||||
-fsanitize=address
|
||||
)
|
||||
target_link_libraries(${bun} PUBLIC
|
||||
-fsanitize=address
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
@@ -964,7 +968,6 @@ if(WIN32)
|
||||
/delayload:WSOCK32.dll
|
||||
/delayload:ADVAPI32.dll
|
||||
/delayload:IPHLPAPI.dll
|
||||
/delayload:CRYPT32.dll
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
@@ -1006,7 +1009,6 @@ if(LINUX)
|
||||
-Wl,--wrap=exp2
|
||||
-Wl,--wrap=expf
|
||||
-Wl,--wrap=fcntl64
|
||||
-Wl,--wrap=gettid
|
||||
-Wl,--wrap=log
|
||||
-Wl,--wrap=log2
|
||||
-Wl,--wrap=log2f
|
||||
@@ -1058,7 +1060,7 @@ if(LINUX)
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT DEBUG AND NOT ENABLE_ASAN AND NOT ENABLE_VALGRIND)
|
||||
if (NOT DEBUG AND NOT ENABLE_ASAN)
|
||||
target_link_options(${bun} PUBLIC
|
||||
-Wl,-icf=safe
|
||||
)
|
||||
@@ -1123,9 +1125,6 @@ endif()
|
||||
|
||||
include_directories(${WEBKIT_INCLUDE_PATH})
|
||||
|
||||
# Include the generated dependency versions header
|
||||
include_directories(${CMAKE_BINARY_DIR})
|
||||
|
||||
if(NOT WEBKIT_LOCAL AND NOT APPLE)
|
||||
include_directories(${WEBKIT_INCLUDE_PATH}/wtf/unicode)
|
||||
endif()
|
||||
@@ -1185,7 +1184,6 @@ if(WIN32)
|
||||
ntdll
|
||||
userenv
|
||||
dbghelp
|
||||
crypt32
|
||||
wsock32 # ws2_32 required by TransmitFile aka sendfile on windows
|
||||
delayimp.lib
|
||||
)
|
||||
@@ -1207,7 +1205,6 @@ if(NOT BUN_CPP_ONLY)
|
||||
endif()
|
||||
|
||||
if(bunStrip)
|
||||
# First, strip bun-profile.exe to create bun.exe
|
||||
register_command(
|
||||
TARGET
|
||||
${bun}
|
||||
@@ -1228,48 +1225,6 @@ if(NOT BUN_CPP_ONLY)
|
||||
OUTPUTS
|
||||
${BUILD_PATH}/${bunStripExe}
|
||||
)
|
||||
|
||||
# Then sign both executables on Windows
|
||||
if(WIN32 AND ENABLE_WINDOWS_CODESIGNING)
|
||||
set(SIGN_SCRIPT "${CMAKE_SOURCE_DIR}/.buildkite/scripts/sign-windows.ps1")
|
||||
|
||||
# Verify signing script exists
|
||||
if(NOT EXISTS "${SIGN_SCRIPT}")
|
||||
message(FATAL_ERROR "Windows signing script not found: ${SIGN_SCRIPT}")
|
||||
endif()
|
||||
|
||||
# Use PowerShell for Windows code signing (native Windows, no path issues)
|
||||
find_program(POWERSHELL_EXECUTABLE
|
||||
NAMES pwsh.exe powershell.exe
|
||||
PATHS
|
||||
"C:/Program Files/PowerShell/7"
|
||||
"C:/Program Files (x86)/PowerShell/7"
|
||||
"C:/Windows/System32/WindowsPowerShell/v1.0"
|
||||
DOC "Path to PowerShell executable"
|
||||
)
|
||||
|
||||
if(NOT POWERSHELL_EXECUTABLE)
|
||||
set(POWERSHELL_EXECUTABLE "powershell.exe")
|
||||
endif()
|
||||
|
||||
message(STATUS "Using PowerShell executable: ${POWERSHELL_EXECUTABLE}")
|
||||
|
||||
# Sign both bun-profile.exe and bun.exe after stripping
|
||||
register_command(
|
||||
TARGET
|
||||
${bun}
|
||||
TARGET_PHASE
|
||||
POST_BUILD
|
||||
COMMENT
|
||||
"Code signing bun-profile.exe and bun.exe with DigiCert KeyLocker"
|
||||
COMMAND
|
||||
"${POWERSHELL_EXECUTABLE}" "-NoProfile" "-ExecutionPolicy" "Bypass" "-File" "${SIGN_SCRIPT}" "-BunProfileExe" "${BUILD_PATH}/${bunExe}" "-BunExe" "${BUILD_PATH}/${bunStripExe}"
|
||||
CWD
|
||||
${CMAKE_SOURCE_DIR}
|
||||
SOURCES
|
||||
${BUILD_PATH}/${bunStripExe}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# somehow on some Linux systems we need to disable ASLR for ASAN-instrumented binaries to run
|
||||
@@ -1361,20 +1316,12 @@ if(NOT BUN_CPP_ONLY)
|
||||
if(ENABLE_BASELINE)
|
||||
set(bunTriplet ${bunTriplet}-baseline)
|
||||
endif()
|
||||
|
||||
if (ENABLE_ASAN AND ENABLE_VALGRIND)
|
||||
set(bunTriplet ${bunTriplet}-asan-valgrind)
|
||||
set(bunPath ${bunTriplet})
|
||||
elseif (ENABLE_VALGRIND)
|
||||
set(bunTriplet ${bunTriplet}-valgrind)
|
||||
set(bunPath ${bunTriplet})
|
||||
elseif(ENABLE_ASAN)
|
||||
if(ENABLE_ASAN)
|
||||
set(bunTriplet ${bunTriplet}-asan)
|
||||
set(bunPath ${bunTriplet})
|
||||
else()
|
||||
string(REPLACE bun ${bunTriplet} bunPath ${bun})
|
||||
endif()
|
||||
|
||||
set(bunFiles ${bunExe} features.json)
|
||||
if(WIN32)
|
||||
list(APPEND bunFiles ${bun}.pdb)
|
||||
|
||||
@@ -4,7 +4,7 @@ register_repository(
|
||||
REPOSITORY
|
||||
HdrHistogram/HdrHistogram_c
|
||||
COMMIT
|
||||
be60a9987ee48d0abf0d7b6a175bad8d6c1585d1
|
||||
8dcce8f68512fca460b171bccc3a5afce0048779
|
||||
)
|
||||
|
||||
register_cmake_command(
|
||||
|
||||
@@ -4,8 +4,7 @@ register_repository(
|
||||
REPOSITORY
|
||||
libuv/libuv
|
||||
COMMIT
|
||||
# Corresponds to v1.51.0
|
||||
5152db2cbfeb5582e9c27c5ea1dba2cd9e10759b
|
||||
da527d8d2a908b824def74382761566371439003
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
|
||||
@@ -4,7 +4,7 @@ register_repository(
|
||||
REPOSITORY
|
||||
oven-sh/mimalloc
|
||||
COMMIT
|
||||
1beadf9651a7bfdec6b5367c380ecc3fe1c40d1a
|
||||
c90e3981edcf6d75c8243e3d323e4300d700ebc6
|
||||
)
|
||||
|
||||
set(MIMALLOC_CMAKE_ARGS
|
||||
@@ -14,7 +14,7 @@ set(MIMALLOC_CMAKE_ARGS
|
||||
-DMI_BUILD_TESTS=OFF
|
||||
-DMI_USE_CXX=ON
|
||||
-DMI_SKIP_COLLECT_ON_EXIT=ON
|
||||
|
||||
|
||||
# ```
|
||||
# ❯ mimalloc_allow_large_os_pages=0 BUN_PORT=3004 mem bun http-hello.js
|
||||
# Started development server: http://localhost:3004
|
||||
@@ -51,7 +51,7 @@ if(ENABLE_ASAN)
|
||||
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_DEBUG_UBSAN=ON)
|
||||
elseif(APPLE OR LINUX)
|
||||
if(APPLE)
|
||||
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OVERRIDE=OFF)
|
||||
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OVERRIDE=OFF)
|
||||
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OSX_ZONE=OFF)
|
||||
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_OSX_INTERPOSE=OFF)
|
||||
else()
|
||||
|
||||
@@ -1,220 +0,0 @@
|
||||
# GenerateDependencyVersions.cmake
|
||||
# Generates a header file with all dependency versions
|
||||
|
||||
# Function to extract version from git tree object
|
||||
function(get_git_tree_hash dep_name output_var)
|
||||
execute_process(
|
||||
COMMAND git rev-parse HEAD:./src/deps/${dep_name}
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
OUTPUT_VARIABLE commit_hash
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
RESULT_VARIABLE result
|
||||
)
|
||||
if(result EQUAL 0 AND commit_hash)
|
||||
set(${output_var} "${commit_hash}" PARENT_SCOPE)
|
||||
else()
|
||||
set(${output_var} "unknown" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Function to extract version from header file using regex
|
||||
function(extract_version_from_header header_file regex_pattern output_var)
|
||||
if(EXISTS "${header_file}")
|
||||
file(STRINGS "${header_file}" version_line REGEX "${regex_pattern}")
|
||||
if(version_line)
|
||||
string(REGEX MATCH "${regex_pattern}" _match "${version_line}")
|
||||
if(CMAKE_MATCH_1)
|
||||
set(${output_var} "${CMAKE_MATCH_1}" PARENT_SCOPE)
|
||||
else()
|
||||
set(${output_var} "unknown" PARENT_SCOPE)
|
||||
endif()
|
||||
else()
|
||||
set(${output_var} "unknown" PARENT_SCOPE)
|
||||
endif()
|
||||
else()
|
||||
set(${output_var} "unknown" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Main function to generate the header file
|
||||
function(generate_dependency_versions_header)
|
||||
set(DEPS_PATH "${CMAKE_SOURCE_DIR}/src/deps")
|
||||
set(VENDOR_PATH "${CMAKE_SOURCE_DIR}/vendor")
|
||||
|
||||
# Initialize version variables
|
||||
set(DEPENDENCY_VERSIONS "")
|
||||
|
||||
# WebKit version (from SetupWebKit.cmake or command line)
|
||||
if(WEBKIT_VERSION)
|
||||
set(WEBKIT_VERSION_STR "${WEBKIT_VERSION}")
|
||||
else()
|
||||
set(WEBKIT_VERSION_STR "0ddf6f47af0a9782a354f61e06d7f83d097d9f84")
|
||||
endif()
|
||||
list(APPEND DEPENDENCY_VERSIONS "WEBKIT" "${WEBKIT_VERSION_STR}")
|
||||
|
||||
# Track input files so CMake reconfigures when they change
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
|
||||
"${CMAKE_SOURCE_DIR}/package.json"
|
||||
"${VENDOR_PATH}/libdeflate/libdeflate.h"
|
||||
"${VENDOR_PATH}/zlib/zlib.h"
|
||||
"${DEPS_PATH}/zstd/lib/zstd.h"
|
||||
)
|
||||
|
||||
# Hardcoded dependency versions (previously from generated_versions_list.zig)
|
||||
# These are the commit hashes/tree objects for each dependency
|
||||
list(APPEND DEPENDENCY_VERSIONS "BORINGSSL" "29a2cd359458c9384694b75456026e4b57e3e567")
|
||||
list(APPEND DEPENDENCY_VERSIONS "C_ARES" "d1722e6e8acaf10eb73fa995798a9cd421d9f85e")
|
||||
list(APPEND DEPENDENCY_VERSIONS "LIBARCHIVE" "898dc8319355b7e985f68a9819f182aaed61b53a")
|
||||
list(APPEND DEPENDENCY_VERSIONS "LIBDEFLATE_HASH" "dc76454a39e7e83b68c3704b6e3784654f8d5ac5")
|
||||
list(APPEND DEPENDENCY_VERSIONS "LOLHTML" "8d4c273ded322193d017042d1f48df2766b0f88b")
|
||||
list(APPEND DEPENDENCY_VERSIONS "LSHPACK" "3d0f1fc1d6e66a642e7a98c55deb38aa986eb4b0")
|
||||
list(APPEND DEPENDENCY_VERSIONS "MIMALLOC" "4c283af60cdae205df5a872530c77e2a6a307d43")
|
||||
list(APPEND DEPENDENCY_VERSIONS "PICOHTTPPARSER" "066d2b1e9ab820703db0837a7255d92d30f0c9f5")
|
||||
list(APPEND DEPENDENCY_VERSIONS "TINYCC" "ab631362d839333660a265d3084d8ff060b96753")
|
||||
list(APPEND DEPENDENCY_VERSIONS "ZLIB_HASH" "886098f3f339617b4243b286f5ed364b9989e245")
|
||||
list(APPEND DEPENDENCY_VERSIONS "ZSTD_HASH" "794ea1b0afca0f020f4e57b6732332231fb23c70")
|
||||
|
||||
# Extract semantic versions from header files where available
|
||||
extract_version_from_header(
|
||||
"${VENDOR_PATH}/libdeflate/libdeflate.h"
|
||||
"#define LIBDEFLATE_VERSION_STRING[ \t]+\"([0-9\\.]+)\""
|
||||
LIBDEFLATE_VERSION_STRING
|
||||
)
|
||||
list(APPEND DEPENDENCY_VERSIONS "LIBDEFLATE_VERSION" "${LIBDEFLATE_VERSION_STRING}")
|
||||
|
||||
extract_version_from_header(
|
||||
"${VENDOR_PATH}/zlib/zlib.h"
|
||||
"#define[ \t]+ZLIB_VERSION[ \t]+\"([^\"]+)\""
|
||||
ZLIB_VERSION_STRING
|
||||
)
|
||||
list(APPEND DEPENDENCY_VERSIONS "ZLIB_VERSION" "${ZLIB_VERSION_STRING}")
|
||||
|
||||
extract_version_from_header(
|
||||
"${DEPS_PATH}/zstd/lib/zstd.h"
|
||||
"#define[ \t]+ZSTD_VERSION_STRING[ \t]+\"([^\"]+)\""
|
||||
ZSTD_VERSION_STRING
|
||||
)
|
||||
list(APPEND DEPENDENCY_VERSIONS "ZSTD_VERSION" "${ZSTD_VERSION_STRING}")
|
||||
|
||||
# Bun version from package.json
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/package.json")
|
||||
file(READ "${CMAKE_SOURCE_DIR}/package.json" PACKAGE_JSON)
|
||||
string(REGEX MATCH "\"version\"[ \t]*:[ \t]*\"([^\"]+)\"" _ ${PACKAGE_JSON})
|
||||
if(CMAKE_MATCH_1)
|
||||
set(BUN_VERSION_STRING "${CMAKE_MATCH_1}")
|
||||
else()
|
||||
set(BUN_VERSION_STRING "unknown")
|
||||
endif()
|
||||
else()
|
||||
set(BUN_VERSION_STRING "${VERSION}")
|
||||
endif()
|
||||
list(APPEND DEPENDENCY_VERSIONS "BUN_VERSION" "${BUN_VERSION_STRING}")
|
||||
|
||||
# Node.js compatibility version (hardcoded as in the current implementation)
|
||||
set(NODEJS_COMPAT_VERSION "22.12.0")
|
||||
list(APPEND DEPENDENCY_VERSIONS "NODEJS_COMPAT_VERSION" "${NODEJS_COMPAT_VERSION}")
|
||||
|
||||
# Get Bun's git SHA for uws/usockets versions (they use Bun's own SHA)
|
||||
execute_process(
|
||||
COMMAND git rev-parse HEAD
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
OUTPUT_VARIABLE BUN_GIT_SHA
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
if(NOT BUN_GIT_SHA)
|
||||
set(BUN_GIT_SHA "unknown")
|
||||
endif()
|
||||
list(APPEND DEPENDENCY_VERSIONS "UWS" "${BUN_GIT_SHA}")
|
||||
list(APPEND DEPENDENCY_VERSIONS "USOCKETS" "${BUN_GIT_SHA}")
|
||||
|
||||
# Zig version - hardcoded for now, can be updated as needed
|
||||
# This should match the version of Zig used to build Bun
|
||||
list(APPEND DEPENDENCY_VERSIONS "ZIG" "0.14.1")
|
||||
|
||||
# Generate the header file content
|
||||
set(HEADER_CONTENT "// This file is auto-generated by CMake. Do not edit manually.\n")
|
||||
string(APPEND HEADER_CONTENT "#ifndef BUN_DEPENDENCY_VERSIONS_H\n")
|
||||
string(APPEND HEADER_CONTENT "#define BUN_DEPENDENCY_VERSIONS_H\n\n")
|
||||
string(APPEND HEADER_CONTENT "#ifdef __cplusplus\n")
|
||||
string(APPEND HEADER_CONTENT "extern \"C\" {\n")
|
||||
string(APPEND HEADER_CONTENT "#endif\n\n")
|
||||
string(APPEND HEADER_CONTENT "// Dependency versions\n")
|
||||
|
||||
# Process the version list
|
||||
list(LENGTH DEPENDENCY_VERSIONS num_versions)
|
||||
math(EXPR last_idx "${num_versions} - 1")
|
||||
set(i 0)
|
||||
while(i LESS num_versions)
|
||||
list(GET DEPENDENCY_VERSIONS ${i} name)
|
||||
math(EXPR value_idx "${i} + 1")
|
||||
if(value_idx LESS num_versions)
|
||||
list(GET DEPENDENCY_VERSIONS ${value_idx} value)
|
||||
# Only emit #define if value is not "unknown"
|
||||
if(NOT "${value}" STREQUAL "unknown")
|
||||
string(APPEND HEADER_CONTENT "#define BUN_DEP_${name} \"${value}\"\n")
|
||||
endif()
|
||||
endif()
|
||||
math(EXPR i "${i} + 2")
|
||||
endwhile()
|
||||
|
||||
string(APPEND HEADER_CONTENT "\n")
|
||||
string(APPEND HEADER_CONTENT "// C string constants for easy access\n")
|
||||
|
||||
# Create C string constants
|
||||
set(i 0)
|
||||
while(i LESS num_versions)
|
||||
list(GET DEPENDENCY_VERSIONS ${i} name)
|
||||
math(EXPR value_idx "${i} + 1")
|
||||
if(value_idx LESS num_versions)
|
||||
list(GET DEPENDENCY_VERSIONS ${value_idx} value)
|
||||
# Only emit constant if value is not "unknown"
|
||||
if(NOT "${value}" STREQUAL "unknown")
|
||||
string(APPEND HEADER_CONTENT "static const char* const BUN_VERSION_${name} = \"${value}\";\n")
|
||||
endif()
|
||||
endif()
|
||||
math(EXPR i "${i} + 2")
|
||||
endwhile()
|
||||
|
||||
string(APPEND HEADER_CONTENT "\n#ifdef __cplusplus\n")
|
||||
string(APPEND HEADER_CONTENT "}\n")
|
||||
string(APPEND HEADER_CONTENT "#endif\n\n")
|
||||
string(APPEND HEADER_CONTENT "#endif // BUN_DEPENDENCY_VERSIONS_H\n")
|
||||
|
||||
# Write the header file only if content has changed
|
||||
set(OUTPUT_FILE "${CMAKE_BINARY_DIR}/bun_dependency_versions.h")
|
||||
|
||||
# Read existing content if file exists
|
||||
set(EXISTING_CONTENT "")
|
||||
if(EXISTS "${OUTPUT_FILE}")
|
||||
file(READ "${OUTPUT_FILE}" EXISTING_CONTENT)
|
||||
endif()
|
||||
|
||||
# Only write if content is different
|
||||
if(NOT "${EXISTING_CONTENT}" STREQUAL "${HEADER_CONTENT}")
|
||||
file(WRITE "${OUTPUT_FILE}" "${HEADER_CONTENT}")
|
||||
message(STATUS "Updated dependency versions header: ${OUTPUT_FILE}")
|
||||
else()
|
||||
message(STATUS "Dependency versions header unchanged: ${OUTPUT_FILE}")
|
||||
endif()
|
||||
|
||||
# Also create a more detailed version for debugging
|
||||
set(DEBUG_OUTPUT_FILE "${CMAKE_BINARY_DIR}/bun_dependency_versions_debug.txt")
|
||||
set(DEBUG_CONTENT "Bun Dependency Versions\n")
|
||||
string(APPEND DEBUG_CONTENT "=======================\n\n")
|
||||
set(i 0)
|
||||
while(i LESS num_versions)
|
||||
list(GET DEPENDENCY_VERSIONS ${i} name)
|
||||
math(EXPR value_idx "${i} + 1")
|
||||
if(value_idx LESS num_versions)
|
||||
list(GET DEPENDENCY_VERSIONS ${value_idx} value)
|
||||
string(APPEND DEBUG_CONTENT "${name}: ${value}\n")
|
||||
endif()
|
||||
math(EXPR i "${i} + 2")
|
||||
endwhile()
|
||||
file(WRITE "${DEBUG_OUTPUT_FILE}" "${DEBUG_CONTENT}")
|
||||
endfunction()
|
||||
|
||||
# Call the function to generate the header
|
||||
generate_dependency_versions_header()
|
||||
@@ -131,9 +131,6 @@ else()
|
||||
find_llvm_command(CMAKE_RANLIB llvm-ranlib)
|
||||
if(LINUX)
|
||||
find_llvm_command(LLD_PROGRAM ld.lld)
|
||||
# Ensure vendor dependencies use lld instead of ld
|
||||
list(APPEND CMAKE_ARGS -DCMAKE_EXE_LINKER_FLAGS=--ld-path=${LLD_PROGRAM})
|
||||
list(APPEND CMAKE_ARGS -DCMAKE_SHARED_LINKER_FLAGS=--ld-path=${LLD_PROGRAM})
|
||||
endif()
|
||||
if(APPLE)
|
||||
find_llvm_command(CMAKE_DSYMUTIL dsymutil)
|
||||
|
||||
@@ -2,7 +2,7 @@ option(WEBKIT_VERSION "The version of WebKit to use")
|
||||
option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading")
|
||||
|
||||
if(NOT WEBKIT_VERSION)
|
||||
set(WEBKIT_VERSION 69fa2714ab5f917c2d15501ff8cfdccfaea78882)
|
||||
set(WEBKIT_VERSION 53385bda2d2270223ac66f7b021a4aec3dd6df75)
|
||||
endif()
|
||||
|
||||
string(SUBSTRING ${WEBKIT_VERSION} 0 16 WEBKIT_VERSION_PREFIX)
|
||||
|
||||
@@ -20,7 +20,7 @@ else()
|
||||
unsupported(CMAKE_SYSTEM_NAME)
|
||||
endif()
|
||||
|
||||
set(ZIG_COMMIT "e0b7c318f318196c5f81fdf3423816a7b5bb3112")
|
||||
set(ZIG_COMMIT "edc6229b1fafb1701a25fb4e17114cc756991546")
|
||||
optionx(ZIG_TARGET STRING "The zig target to use" DEFAULT ${DEFAULT_ZIG_TARGET})
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
@@ -90,7 +90,6 @@ register_command(
|
||||
-DZIG_PATH=${ZIG_PATH}
|
||||
-DZIG_COMMIT=${ZIG_COMMIT}
|
||||
-DENABLE_ASAN=${ENABLE_ASAN}
|
||||
-DENABLE_VALGRIND=${ENABLE_VALGRIND}
|
||||
-DZIG_COMPILER_SAFE=${ZIG_COMPILER_SAFE}
|
||||
-P ${CWD}/cmake/scripts/DownloadZig.cmake
|
||||
SOURCES
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
},
|
||||
{
|
||||
"name": "reporter",
|
||||
"description": "Test output reporter format. Available: 'junit' (requires --reporter-outfile). Default: console output.",
|
||||
"description": "Specify the test reporter. Currently --reporter=junit is the only supported format.",
|
||||
"hasValue": true,
|
||||
"valueType": "val",
|
||||
"required": false,
|
||||
@@ -130,7 +130,7 @@
|
||||
},
|
||||
{
|
||||
"name": "reporter-outfile",
|
||||
"description": "Output file path for the reporter format (required with --reporter).",
|
||||
"description": "The output file used for the format from --reporter.",
|
||||
"hasValue": true,
|
||||
"valueType": "val",
|
||||
"required": false,
|
||||
|
||||
@@ -665,6 +665,7 @@ _bun_test_completion() {
|
||||
'--timeout[Set the per-test timeout in milliseconds, default is 5000.]:timeout' \
|
||||
'--update-snapshots[Update snapshot files]' \
|
||||
'--rerun-each[Re-run each test file <NUMBER> times, helps catch certain bugs]:rerun' \
|
||||
'--only[Only run tests that are marked with "test.only()"]' \
|
||||
'--todo[Include tests that are marked with "test.todo()"]' \
|
||||
'--coverage[Generate a coverage profile]' \
|
||||
'--bail[Exit the test suite after <NUMBER> failures. If you do not specify a number, it defaults to 1.]:bail' \
|
||||
|
||||
@@ -184,7 +184,6 @@ Bun.hash.rapidhash("data", 1234);
|
||||
|
||||
- `"blake2b256"`
|
||||
- `"blake2b512"`
|
||||
- `"blake2s256"`
|
||||
- `"md4"`
|
||||
- `"md5"`
|
||||
- `"ripemd160"`
|
||||
|
||||
@@ -161,102 +161,6 @@ const randomTag = await redis.srandmember("tags");
|
||||
const poppedTag = await redis.spop("tags");
|
||||
```
|
||||
|
||||
## Pub/Sub
|
||||
|
||||
Bun provides native bindings for the [Redis
|
||||
Pub/Sub](https://redis.io/docs/latest/develop/pubsub/) protocol. **New in Bun
|
||||
1.2.23**
|
||||
|
||||
{% callout %}
|
||||
**🚧** — The Redis Pub/Sub feature is experimental. Although we expect it to be
|
||||
stable, we're currently actively looking for feedback and areas for improvement.
|
||||
{% /callout %}
|
||||
|
||||
### Basic Usage
|
||||
|
||||
To get started publishing messages, you can set up a publisher in
|
||||
`publisher.ts`:
|
||||
|
||||
```typescript#publisher.ts
|
||||
import { RedisClient } from "bun";
|
||||
|
||||
const writer = new RedisClient("redis://localhost:6739");
|
||||
await writer.connect();
|
||||
|
||||
writer.publish("general", "Hello everyone!");
|
||||
|
||||
writer.close();
|
||||
```
|
||||
|
||||
In another file, create the subscriber in `subscriber.ts`:
|
||||
|
||||
```typescript#subscriber.ts
|
||||
import { RedisClient } from "bun";
|
||||
|
||||
const listener = new RedisClient("redis://localhost:6739");
|
||||
await listener.connect();
|
||||
|
||||
await listener.subscribe("general", (message, channel) => {
|
||||
console.log(`Received: ${message}`);
|
||||
});
|
||||
```
|
||||
|
||||
In one shell, run your subscriber:
|
||||
|
||||
```bash
|
||||
bun run subscriber.ts
|
||||
```
|
||||
|
||||
and, in another, run your publisher:
|
||||
|
||||
```bash
|
||||
bun run publisher.ts
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
**Note:** The subscription mode takes over the `RedisClient` connection. A
|
||||
client with subscriptions can only call `RedisClient.prototype.subscribe()`. In
|
||||
other words, applications which need to message Redis need a separate
|
||||
connection, acquirable through `.duplicate()`:
|
||||
|
||||
```typescript
|
||||
import { RedisClient } from "bun";
|
||||
|
||||
const redis = new RedisClient("redis://localhost:6379");
|
||||
await redis.connect();
|
||||
const subscriber = await redis.duplicate();
|
||||
|
||||
await subscriber.subscribe("foo", () => {});
|
||||
await redis.set("bar", "baz");
|
||||
```
|
||||
|
||||
{% /callout %}
|
||||
|
||||
### Publishing
|
||||
|
||||
Publishing messages is done through the `publish()` method:
|
||||
|
||||
```typescript
|
||||
await client.publish(channelName, message);
|
||||
```
|
||||
|
||||
### Subscriptions
|
||||
|
||||
The Bun `RedisClient` allows you to subscribe to channels through the
|
||||
`.subscribe()` method:
|
||||
|
||||
```typescript
|
||||
await client.subscribe(channel, (message, channel) => {});
|
||||
```
|
||||
|
||||
You can unsubscribe through the `.unsubscribe()` method:
|
||||
|
||||
```typescript
|
||||
await client.unsubscribe(); // Unsubscribe from all channels.
|
||||
await client.unsubscribe(channel); // Unsubscribe a particular channel.
|
||||
await client.unsubscribe(channel, listener); // Unsubscribe a particular listener.
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Command Execution and Pipelining
|
||||
@@ -578,10 +482,9 @@ When connecting to Redis servers using older versions that don't support RESP3,
|
||||
|
||||
Current limitations of the Redis client we are planning to address in future versions:
|
||||
|
||||
- [ ] No dedicated API for pub/sub functionality (though you can use the raw command API)
|
||||
- [ ] Transactions (MULTI/EXEC) must be done through raw commands for now
|
||||
- [ ] Streams are supported but without dedicated methods
|
||||
- [ ] Pub/Sub does not currently support binary data, nor pattern-based
|
||||
subscriptions.
|
||||
|
||||
Unsupported features:
|
||||
|
||||
|
||||
@@ -1,319 +0,0 @@
|
||||
Store and retrieve sensitive credentials securely using the operating system's native credential storage APIs.
|
||||
|
||||
**Experimental:** This API is new and experimental. It may change in the future.
|
||||
|
||||
```typescript
|
||||
import { secrets } from "bun";
|
||||
|
||||
const githubToken = await secrets.get({
|
||||
service: "my-cli-tool",
|
||||
name: "github-token",
|
||||
});
|
||||
|
||||
if (!githubToken) {
|
||||
const response = await fetch("https://api.github.com/name", {
|
||||
headers: { "Authorization": `token ${githubToken}` },
|
||||
});
|
||||
console.log("Please enter your GitHub token");
|
||||
} else {
|
||||
await secrets.set({
|
||||
service: "my-cli-tool",
|
||||
name: "github-token",
|
||||
value: prompt("Please enter your GitHub token"),
|
||||
});
|
||||
console.log("GitHub token stored");
|
||||
}
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
`Bun.secrets` provides a cross-platform API for managing sensitive credentials that CLI tools and development applications typically store in plaintext files like `~/.npmrc`, `~/.aws/credentials`, or `.env` files. It uses:
|
||||
|
||||
- **macOS**: Keychain Services
|
||||
- **Linux**: libsecret (GNOME Keyring, KWallet, etc.)
|
||||
- **Windows**: Windows Credential Manager
|
||||
|
||||
All operations are asynchronous and non-blocking, running on Bun's threadpool.
|
||||
|
||||
Note: in the future, we may add an additional `provider` option to make this better for production deployment secrets, but today this API is mostly useful for local development tools.
|
||||
|
||||
## API
|
||||
|
||||
### `Bun.secrets.get(options)`
|
||||
|
||||
Retrieve a stored credential.
|
||||
|
||||
```typescript
|
||||
import { secrets } from "bun";
|
||||
|
||||
const password = await Bun.secrets.get({
|
||||
service: "my-app",
|
||||
name: "alice@example.com",
|
||||
});
|
||||
// Returns: string | null
|
||||
|
||||
// Or if you prefer without an object
|
||||
const password = await Bun.secrets.get("my-app", "alice@example.com");
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `options.service` (string, required) - The service or application name
|
||||
- `options.name` (string, required) - The username or account identifier
|
||||
|
||||
**Returns:**
|
||||
|
||||
- `Promise<string | null>` - The stored password, or `null` if not found
|
||||
|
||||
### `Bun.secrets.set(options, value)`
|
||||
|
||||
Store or update a credential.
|
||||
|
||||
```typescript
|
||||
import { secrets } from "bun";
|
||||
|
||||
await secrets.set({
|
||||
service: "my-app",
|
||||
name: "alice@example.com",
|
||||
value: "super-secret-password",
|
||||
});
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `options.service` (string, required) - The service or application name
|
||||
- `options.name` (string, required) - The username or account identifier
|
||||
- `value` (string, required) - The password or secret to store
|
||||
|
||||
**Notes:**
|
||||
|
||||
- If a credential already exists for the given service/name combination, it will be replaced
|
||||
- The stored value is encrypted by the operating system
|
||||
|
||||
### `Bun.secrets.delete(options)`
|
||||
|
||||
Delete a stored credential.
|
||||
|
||||
```typescript
|
||||
const deleted = await Bun.secrets.delete({
|
||||
service: "my-app",
|
||||
name: "alice@example.com",
|
||||
value: "super-secret-password",
|
||||
});
|
||||
// Returns: boolean
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `options.service` (string, required) - The service or application name
|
||||
- `options.name` (string, required) - The username or account identifier
|
||||
|
||||
**Returns:**
|
||||
|
||||
- `Promise<boolean>` - `true` if a credential was deleted, `false` if not found
|
||||
|
||||
## Examples
|
||||
|
||||
### Storing CLI Tool Credentials
|
||||
|
||||
```javascript
|
||||
// Store GitHub CLI token (instead of ~/.config/gh/hosts.yml)
|
||||
await Bun.secrets.set({
|
||||
service: "my-app.com",
|
||||
name: "github-token",
|
||||
value: "ghp_xxxxxxxxxxxxxxxxxxxx",
|
||||
});
|
||||
|
||||
// Or if you prefer without an object
|
||||
await Bun.secrets.set("my-app.com", "github-token", "ghp_xxxxxxxxxxxxxxxxxxxx");
|
||||
|
||||
// Store npm registry token (instead of ~/.npmrc)
|
||||
await Bun.secrets.set({
|
||||
service: "npm-registry",
|
||||
name: "https://registry.npmjs.org",
|
||||
value: "npm_xxxxxxxxxxxxxxxxxxxx",
|
||||
});
|
||||
|
||||
// Retrieve for API calls
|
||||
const token = await Bun.secrets.get({
|
||||
service: "gh-cli",
|
||||
name: "github.com",
|
||||
});
|
||||
|
||||
if (token) {
|
||||
const response = await fetch("https://api.github.com/name", {
|
||||
headers: {
|
||||
"Authorization": `token ${token}`,
|
||||
},
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Migrating from Plaintext Config Files
|
||||
|
||||
```javascript
|
||||
// Instead of storing in ~/.aws/credentials
|
||||
await Bun.secrets.set({
|
||||
service: "aws-cli",
|
||||
name: "AWS_SECRET_ACCESS_KEY",
|
||||
value: process.env.AWS_SECRET_ACCESS_KEY,
|
||||
});
|
||||
|
||||
// Instead of .env files with sensitive data
|
||||
await Bun.secrets.set({
|
||||
service: "my-app",
|
||||
name: "api-key",
|
||||
value: "sk_live_xxxxxxxxxxxxxxxxxxxx",
|
||||
});
|
||||
|
||||
// Load at runtime
|
||||
const apiKey =
|
||||
(await Bun.secrets.get({
|
||||
service: "my-app",
|
||||
name: "api-key",
|
||||
})) || process.env.API_KEY; // Fallback for CI/production
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
```javascript
|
||||
try {
|
||||
await Bun.secrets.set({
|
||||
service: "my-app",
|
||||
name: "alice",
|
||||
value: "password123",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to store credential:", error.message);
|
||||
}
|
||||
|
||||
// Check if a credential exists
|
||||
const password = await Bun.secrets.get({
|
||||
service: "my-app",
|
||||
name: "alice",
|
||||
});
|
||||
|
||||
if (password === null) {
|
||||
console.log("No credential found");
|
||||
}
|
||||
```
|
||||
|
||||
### Updating Credentials
|
||||
|
||||
```javascript
|
||||
// Initial password
|
||||
await Bun.secrets.set({
|
||||
service: "email-server",
|
||||
name: "admin@example.com",
|
||||
value: "old-password",
|
||||
});
|
||||
|
||||
// Update to new password
|
||||
await Bun.secrets.set({
|
||||
service: "email-server",
|
||||
name: "admin@example.com",
|
||||
value: "new-password",
|
||||
});
|
||||
|
||||
// The old password is replaced
|
||||
```
|
||||
|
||||
## Platform Behavior
|
||||
|
||||
### macOS (Keychain)
|
||||
|
||||
- Credentials are stored in the name's login keychain
|
||||
- The keychain may prompt for access permission on first use
|
||||
- Credentials persist across system restarts
|
||||
- Accessible by the name who stored them
|
||||
|
||||
### Linux (libsecret)
|
||||
|
||||
- Requires a secret service daemon (GNOME Keyring, KWallet, etc.)
|
||||
- Credentials are stored in the default collection
|
||||
- May prompt for unlock if the keyring is locked
|
||||
- The secret service must be running
|
||||
|
||||
### Windows (Credential Manager)
|
||||
|
||||
- Credentials are stored in Windows Credential Manager
|
||||
- Visible in Control Panel → Credential Manager → Windows Credentials
|
||||
- Persist with `CRED_PERSIST_ENTERPRISE` flag so it's scoped per user
|
||||
- Encrypted using Windows Data Protection API
|
||||
|
||||
## Security Considerations
|
||||
|
||||
1. **Encryption**: Credentials are encrypted by the operating system's credential manager
|
||||
2. **Access Control**: Only the name who stored the credential can retrieve it
|
||||
3. **No Plain Text**: Passwords are never stored in plain text
|
||||
4. **Memory Safety**: Bun zeros out password memory after use
|
||||
5. **Process Isolation**: Credentials are isolated per name account
|
||||
|
||||
## Limitations
|
||||
|
||||
- Maximum password length varies by platform (typically 2048-4096 bytes)
|
||||
- Service and name names should be reasonable lengths (< 256 characters)
|
||||
- Some special characters may need escaping depending on the platform
|
||||
- Requires appropriate system services:
|
||||
- Linux: Secret service daemon must be running
|
||||
- macOS: Keychain Access must be available
|
||||
- Windows: Credential Manager service must be enabled
|
||||
|
||||
## Comparison with Environment Variables
|
||||
|
||||
Unlike environment variables, `Bun.secrets`:
|
||||
|
||||
- ✅ Encrypts credentials at rest (thanks to the operating system)
|
||||
- ✅ Avoids exposing secrets in process memory dumps (memory is zeroed after its no longer needed)
|
||||
- ✅ Survives application restarts
|
||||
- ✅ Can be updated without restarting the application
|
||||
- ✅ Provides name-level access control
|
||||
- ❌ Requires OS credential service
|
||||
- ❌ Not very useful for deployment secrets (use environment variables in production)
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use descriptive service names**: Match the tool or application name
|
||||
If you're building a CLI for external use, you probably should use a UTI (Uniform Type Identifier) for the service name.
|
||||
|
||||
```javascript
|
||||
// Good - matches the actual tool
|
||||
{ service: "com.docker.hub", name: "username" }
|
||||
{ service: "com.vercel.cli", name: "team-name" }
|
||||
|
||||
// Avoid - too generic
|
||||
{ service: "api", name: "key" }
|
||||
```
|
||||
|
||||
2. **Credentials-only**: Don't store application configuration in this API
|
||||
This API is slow, you probably still need to use a config file for some things.
|
||||
|
||||
3. **Use for local development tools**:
|
||||
- ✅ CLI tools (gh, npm, docker, kubectl)
|
||||
- ✅ Local development servers
|
||||
- ✅ Personal API keys for testing
|
||||
- ❌ Production servers (use proper secret management)
|
||||
|
||||
## TypeScript
|
||||
|
||||
```typescript
|
||||
namespace Bun {
|
||||
interface SecretsOptions {
|
||||
service: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface Secrets {
|
||||
get(options: SecretsOptions): Promise<string | null>;
|
||||
set(options: SecretsOptions, value: string): Promise<void>;
|
||||
delete(options: SecretsOptions): Promise<boolean>;
|
||||
}
|
||||
|
||||
const secrets: Secrets;
|
||||
}
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
- [Environment Variables](./env.md) - For deployment configuration
|
||||
- [Bun.password](./password.md) - For password hashing and verification
|
||||
388
docs/api/sql.md
388
docs/api/sql.md
@@ -1,4 +1,4 @@
|
||||
Bun provides native bindings for working with SQL databases through a unified Promise-based API that supports PostgreSQL, MySQL, and SQLite. The interface is designed to be simple and performant, using tagged template literals for queries and offering features like connection pooling, transactions, and prepared statements.
|
||||
Bun provides native bindings for working with SQL databases through a unified Promise-based API that supports both PostgreSQL and SQLite. The interface is designed to be simple and performant, using tagged template literals for queries and offering features like connection pooling, transactions, and prepared statements.
|
||||
|
||||
```ts
|
||||
import { sql, SQL } from "bun";
|
||||
@@ -10,16 +10,9 @@ const users = await sql`
|
||||
LIMIT ${10}
|
||||
`;
|
||||
|
||||
// With MySQL
|
||||
const mysql = new SQL("mysql://user:pass@localhost:3306/mydb");
|
||||
const mysqlResults = await mysql`
|
||||
SELECT * FROM users
|
||||
WHERE active = ${true}
|
||||
`;
|
||||
|
||||
// With SQLite
|
||||
// With a a SQLite db
|
||||
const sqlite = new SQL("sqlite://myapp.db");
|
||||
const sqliteResults = await sqlite`
|
||||
const results = await sqlite`
|
||||
SELECT * FROM users
|
||||
WHERE active = ${1}
|
||||
`;
|
||||
@@ -59,7 +52,7 @@ Bun.SQL provides a unified API for multiple database systems:
|
||||
|
||||
PostgreSQL is used when:
|
||||
|
||||
- The connection string doesn't match SQLite or MySQL patterns (it's the fallback adapter)
|
||||
- The connection string doesn't match SQLite patterns (it's the fallback adapter)
|
||||
- The connection string explicitly uses `postgres://` or `postgresql://` protocols
|
||||
- No connection string is provided and environment variables point to PostgreSQL
|
||||
|
||||
@@ -73,82 +66,9 @@ const pg = new SQL("postgres://user:pass@localhost:5432/mydb");
|
||||
await pg`SELECT ...`;
|
||||
```
|
||||
|
||||
### MySQL
|
||||
|
||||
MySQL support is built into Bun.SQL, providing the same tagged template literal interface with full compatibility for MySQL 5.7+ and MySQL 8.0+:
|
||||
|
||||
```ts
|
||||
import { SQL } from "bun";
|
||||
|
||||
// MySQL connection
|
||||
const mysql = new SQL("mysql://user:password@localhost:3306/database");
|
||||
const mysql2 = new SQL("mysql2://user:password@localhost:3306/database"); // mysql2 protocol also works
|
||||
|
||||
// Using options object
|
||||
const mysql3 = new SQL({
|
||||
adapter: "mysql",
|
||||
hostname: "localhost",
|
||||
port: 3306,
|
||||
database: "myapp",
|
||||
username: "dbuser",
|
||||
password: "secretpass",
|
||||
});
|
||||
|
||||
// Works with parameters - automatically uses prepared statements
|
||||
const users = await mysql`SELECT * FROM users WHERE id = ${userId}`;
|
||||
|
||||
// Transactions work the same as PostgreSQL
|
||||
await mysql.begin(async tx => {
|
||||
await tx`INSERT INTO users (name) VALUES (${"Alice"})`;
|
||||
await tx`UPDATE accounts SET balance = balance - 100 WHERE user_id = ${userId}`;
|
||||
});
|
||||
|
||||
// Bulk inserts
|
||||
const newUsers = [
|
||||
{ name: "Alice", email: "alice@example.com" },
|
||||
{ name: "Bob", email: "bob@example.com" },
|
||||
];
|
||||
await mysql`INSERT INTO users ${mysql(newUsers)}`;
|
||||
```
|
||||
|
||||
{% details summary="MySQL Connection String Formats" %}
|
||||
|
||||
MySQL accepts various URL formats for connection strings:
|
||||
|
||||
```ts
|
||||
// Standard mysql:// protocol
|
||||
new SQL("mysql://user:pass@localhost:3306/database");
|
||||
new SQL("mysql://user:pass@localhost/database"); // Default port 3306
|
||||
|
||||
// mysql2:// protocol (compatibility with mysql2 npm package)
|
||||
new SQL("mysql2://user:pass@localhost:3306/database");
|
||||
|
||||
// With query parameters
|
||||
new SQL("mysql://user:pass@localhost/db?ssl=true");
|
||||
|
||||
// Unix socket connection
|
||||
new SQL("mysql://user:pass@/database?socket=/var/run/mysqld/mysqld.sock");
|
||||
```
|
||||
|
||||
{% /details %}
|
||||
|
||||
{% details summary="MySQL-Specific Features" %}
|
||||
|
||||
MySQL databases support:
|
||||
|
||||
- **Prepared statements**: Automatically created for parameterized queries with statement caching
|
||||
- **Binary protocol**: For better performance with prepared statements and accurate type handling
|
||||
- **Multiple result sets**: Support for stored procedures returning multiple result sets
|
||||
- **Authentication plugins**: Support for mysql_native_password, caching_sha2_password (MySQL 8.0 default), and sha256_password
|
||||
- **SSL/TLS connections**: Configurable SSL modes similar to PostgreSQL
|
||||
- **Connection attributes**: Client information sent to server for monitoring
|
||||
- **Query pipelining**: Execute multiple prepared statements without waiting for responses
|
||||
|
||||
{% /details %}
|
||||
|
||||
### SQLite
|
||||
|
||||
SQLite support is built into Bun.SQL, providing the same tagged template literal interface:
|
||||
SQLite support is now built into Bun.SQL, providing the same tagged template literal interface as PostgreSQL:
|
||||
|
||||
```ts
|
||||
import { SQL } from "bun";
|
||||
@@ -170,7 +90,8 @@ const db2 = new SQL({
|
||||
const db3 = new SQL("myapp.db", { adapter: "sqlite" });
|
||||
```
|
||||
|
||||
{% details summary="SQLite Connection String Formats" %}
|
||||
<details>
|
||||
<summary>SQLite Connection String Formats</summary>
|
||||
|
||||
SQLite accepts various URL formats for connection strings:
|
||||
|
||||
@@ -201,9 +122,10 @@ new SQL("sqlite://data.db?mode=rwc"); // Read-write-create mode (default)
|
||||
|
||||
**Note:** Simple filenames without a protocol (like `"myapp.db"`) require explicitly specifying `{ adapter: "sqlite" }` to avoid ambiguity with PostgreSQL.
|
||||
|
||||
{% /details %}
|
||||
</details>
|
||||
|
||||
{% details summary="SQLite-Specific Options" %}
|
||||
<details>
|
||||
<summary>SQLite-Specific Options</summary>
|
||||
|
||||
SQLite databases support additional configuration options:
|
||||
|
||||
@@ -229,7 +151,7 @@ Query parameters in the URL are parsed to set these options:
|
||||
- `?mode=rw` → `readonly: false, create: false`
|
||||
- `?mode=rwc` → `readonly: false, create: true` (default)
|
||||
|
||||
{% /details %}
|
||||
</details>
|
||||
|
||||
### Inserting data
|
||||
|
||||
@@ -442,24 +364,7 @@ await query;
|
||||
|
||||
### Automatic Database Detection
|
||||
|
||||
When using `Bun.sql()` without arguments or `new SQL()` with a connection string, the adapter is automatically detected based on the URL format:
|
||||
|
||||
#### MySQL Auto-Detection
|
||||
|
||||
MySQL is automatically selected when the connection string matches these patterns:
|
||||
|
||||
- `mysql://...` - MySQL protocol URLs
|
||||
- `mysql2://...` - MySQL2 protocol URLs (compatibility alias)
|
||||
|
||||
```ts
|
||||
// These all use MySQL automatically (no adapter needed)
|
||||
const sql1 = new SQL("mysql://user:pass@localhost/mydb");
|
||||
const sql2 = new SQL("mysql2://user:pass@localhost:3306/mydb");
|
||||
|
||||
// Works with DATABASE_URL environment variable
|
||||
DATABASE_URL="mysql://user:pass@localhost/mydb" bun run app.js
|
||||
DATABASE_URL="mysql2://user:pass@localhost:3306/mydb" bun run app.js
|
||||
```
|
||||
When using `Bun.sql()` without arguments or `new SQL()` with a connection string, the adapter is automatically detected based on the URL format. SQLite becomes the default adapter in these cases:
|
||||
|
||||
#### SQLite Auto-Detection
|
||||
|
||||
@@ -485,42 +390,17 @@ DATABASE_URL="file://./data/app.db" bun run app.js
|
||||
|
||||
#### PostgreSQL Auto-Detection
|
||||
|
||||
PostgreSQL is the default for connection strings that don't match MySQL or SQLite patterns:
|
||||
PostgreSQL is the default for all other connection strings:
|
||||
|
||||
```bash
|
||||
# PostgreSQL is detected for these patterns
|
||||
DATABASE_URL="postgres://user:pass@localhost:5432/mydb" bun run app.js
|
||||
DATABASE_URL="postgresql://user:pass@localhost:5432/mydb" bun run app.js
|
||||
|
||||
# Or any URL that doesn't match MySQL or SQLite patterns
|
||||
# Or any URL that doesn't match SQLite patterns
|
||||
DATABASE_URL="localhost:5432/mydb" bun run app.js
|
||||
```
|
||||
|
||||
### MySQL Environment Variables
|
||||
|
||||
MySQL connections can be configured via environment variables:
|
||||
|
||||
```bash
|
||||
# Primary connection URL (checked first)
|
||||
MYSQL_URL="mysql://user:pass@localhost:3306/mydb"
|
||||
|
||||
# Alternative: DATABASE_URL with MySQL protocol
|
||||
DATABASE_URL="mysql://user:pass@localhost:3306/mydb"
|
||||
DATABASE_URL="mysql2://user:pass@localhost:3306/mydb"
|
||||
```
|
||||
|
||||
If no connection URL is provided, MySQL checks these individual parameters:
|
||||
|
||||
| Environment Variable | Default Value | Description |
|
||||
| ------------------------ | ------------- | -------------------------------- |
|
||||
| `MYSQL_HOST` | `localhost` | Database host |
|
||||
| `MYSQL_PORT` | `3306` | Database port |
|
||||
| `MYSQL_USER` | `root` | Database user |
|
||||
| `MYSQL_PASSWORD` | (empty) | Database password |
|
||||
| `MYSQL_DATABASE` | `mysql` | Database name |
|
||||
| `MYSQL_URL` | (empty) | Primary connection URL for MySQL |
|
||||
| `TLS_MYSQL_DATABASE_URL` | (empty) | SSL/TLS-enabled connection URL |
|
||||
|
||||
### PostgreSQL Environment Variables
|
||||
|
||||
The following environment variables can be used to define the PostgreSQL connection:
|
||||
@@ -578,53 +458,6 @@ The `--sql-preconnect` flag will automatically establish a PostgreSQL connection
|
||||
|
||||
You can configure your database connection manually by passing options to the SQL constructor. Options vary depending on the database adapter:
|
||||
|
||||
### MySQL Options
|
||||
|
||||
```ts
|
||||
import { SQL } from "bun";
|
||||
|
||||
const db = new SQL({
|
||||
// Required for MySQL when using options object
|
||||
adapter: "mysql",
|
||||
|
||||
// Connection details
|
||||
hostname: "localhost",
|
||||
port: 3306,
|
||||
database: "myapp",
|
||||
username: "dbuser",
|
||||
password: "secretpass",
|
||||
|
||||
// Unix socket connection (alternative to hostname/port)
|
||||
// socket: "/var/run/mysqld/mysqld.sock",
|
||||
|
||||
// Connection pool settings
|
||||
max: 20, // Maximum connections in pool (default: 10)
|
||||
idleTimeout: 30, // Close idle connections after 30s
|
||||
maxLifetime: 0, // Connection lifetime in seconds (0 = forever)
|
||||
connectionTimeout: 30, // Timeout when establishing new connections
|
||||
|
||||
// SSL/TLS options
|
||||
tls: {
|
||||
rejectUnauthorized: true,
|
||||
ca: "path/to/ca.pem",
|
||||
key: "path/to/key.pem",
|
||||
cert: "path/to/cert.pem",
|
||||
},
|
||||
|
||||
// Callbacks
|
||||
onconnect: client => {
|
||||
console.log("Connected to MySQL");
|
||||
},
|
||||
onclose: (client, err) => {
|
||||
if (err) {
|
||||
console.error("MySQL connection error:", err);
|
||||
} else {
|
||||
console.log("MySQL connection closed");
|
||||
}
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### PostgreSQL Options
|
||||
|
||||
```ts
|
||||
@@ -699,14 +532,15 @@ const db = new SQL({
|
||||
});
|
||||
```
|
||||
|
||||
{% details summary="SQLite Connection Notes" %}
|
||||
<details>
|
||||
<summary>SQLite Connection Notes</summary>
|
||||
|
||||
- **Connection Pooling**: SQLite doesn't use connection pooling as it's a file-based database. Each `SQL` instance represents a single connection.
|
||||
- **Transactions**: SQLite supports nested transactions through savepoints, similar to PostgreSQL.
|
||||
- **Concurrent Access**: SQLite handles concurrent access through file locking. Use WAL mode for better concurrency.
|
||||
- **Memory Databases**: Using `:memory:` creates a temporary database that exists only for the connection lifetime.
|
||||
|
||||
{% /details %}
|
||||
</details>
|
||||
|
||||
## Dynamic passwords
|
||||
|
||||
@@ -1004,8 +838,6 @@ try {
|
||||
}
|
||||
```
|
||||
|
||||
{% details summary="PostgreSQL-Specific Error Codes" %}
|
||||
|
||||
### PostgreSQL Connection Errors
|
||||
|
||||
| Connection Errors | Description |
|
||||
@@ -1071,13 +903,12 @@ try {
|
||||
| `ERR_POSTGRES_UNSAFE_TRANSACTION` | Unsafe transaction operation detected |
|
||||
| `ERR_POSTGRES_INVALID_TRANSACTION_STATE` | Invalid transaction state |
|
||||
|
||||
{% /details %}
|
||||
|
||||
### SQLite-Specific Errors
|
||||
|
||||
SQLite errors provide error codes and numbers that correspond to SQLite's standard error codes:
|
||||
|
||||
{% details summary="Common SQLite Error Codes" %}
|
||||
<details>
|
||||
<summary>Common SQLite Error Codes</summary>
|
||||
|
||||
| Error Code | errno | Description |
|
||||
| ------------------- | ----- | ---------------------------------------------------- |
|
||||
@@ -1114,7 +945,7 @@ try {
|
||||
}
|
||||
```
|
||||
|
||||
{% /details %}
|
||||
</details>
|
||||
|
||||
## Numbers and BigInt
|
||||
|
||||
@@ -1148,106 +979,11 @@ console.log(typeof x, x); // "bigint" 9223372036854777n
|
||||
There's still some things we haven't finished yet.
|
||||
|
||||
- Connection preloading via `--db-preconnect` Bun CLI flag
|
||||
- MySQL support: [we're working on it](https://github.com/oven-sh/bun/pull/15274)
|
||||
- Column name transforms (e.g. `snake_case` to `camelCase`). This is mostly blocked on a unicode-aware implementation of changing the case in C++ using WebKit's `WTF::String`.
|
||||
- Column type transforms
|
||||
|
||||
## Database-Specific Features
|
||||
|
||||
#### Authentication Methods
|
||||
|
||||
MySQL supports multiple authentication plugins that are automatically negotiated:
|
||||
|
||||
- **`mysql_native_password`** - Traditional MySQL authentication, widely compatible
|
||||
- **`caching_sha2_password`** - Default in MySQL 8.0+, more secure with RSA key exchange
|
||||
- **`sha256_password`** - SHA-256 based authentication
|
||||
|
||||
The client automatically handles authentication plugin switching when requested by the server, including secure password exchange over non-SSL connections.
|
||||
|
||||
#### Prepared Statements & Performance
|
||||
|
||||
MySQL uses server-side prepared statements for all parameterized queries:
|
||||
|
||||
```ts
|
||||
// This automatically creates a prepared statement on the server
|
||||
const user = await mysql`SELECT * FROM users WHERE id = ${userId}`;
|
||||
|
||||
// Prepared statements are cached and reused for identical queries
|
||||
for (const id of userIds) {
|
||||
// Same prepared statement is reused
|
||||
await mysql`SELECT * FROM users WHERE id = ${id}`;
|
||||
}
|
||||
|
||||
// Query pipelining - multiple statements sent without waiting
|
||||
const [users, orders, products] = await Promise.all([
|
||||
mysql`SELECT * FROM users WHERE active = ${true}`,
|
||||
mysql`SELECT * FROM orders WHERE status = ${"pending"}`,
|
||||
mysql`SELECT * FROM products WHERE in_stock = ${true}`,
|
||||
]);
|
||||
```
|
||||
|
||||
#### Multiple Result Sets
|
||||
|
||||
MySQL can return multiple result sets from multi-statement queries:
|
||||
|
||||
```ts
|
||||
const mysql = new SQL("mysql://user:pass@localhost/mydb");
|
||||
|
||||
// Multi-statement queries with simple() method
|
||||
const multiResults = await mysql`
|
||||
SELECT * FROM users WHERE id = 1;
|
||||
SELECT * FROM orders WHERE user_id = 1;
|
||||
`.simple();
|
||||
```
|
||||
|
||||
#### Character Sets & Collations
|
||||
|
||||
Bun.SQL automatically uses `utf8mb4` character set for MySQL connections, ensuring full Unicode support including emojis. This is the recommended character set for modern MySQL applications.
|
||||
|
||||
#### Connection Attributes
|
||||
|
||||
Bun automatically sends client information to MySQL for better monitoring:
|
||||
|
||||
```ts
|
||||
// These attributes are sent automatically:
|
||||
// _client_name: "Bun"
|
||||
// _client_version: <bun version>
|
||||
// You can see these in MySQL's performance_schema.session_connect_attrs
|
||||
```
|
||||
|
||||
#### Type Handling
|
||||
|
||||
MySQL types are automatically converted to JavaScript types:
|
||||
|
||||
| MySQL Type | JavaScript Type | Notes |
|
||||
| --------------------------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------- |
|
||||
| INT, TINYINT, MEDIUMINT | number | Within safe integer range |
|
||||
| BIGINT | string, number or BigInt | If the value fits in i32/u32 size will be number otherwise string or BigInt Based on `bigint` option |
|
||||
| DECIMAL, NUMERIC | string | To preserve precision |
|
||||
| FLOAT, DOUBLE | number | |
|
||||
| DATE | Date | JavaScript Date object |
|
||||
| DATETIME, TIMESTAMP | Date | With timezone handling |
|
||||
| TIME | number | Total of microseconds |
|
||||
| YEAR | number | |
|
||||
| CHAR, VARCHAR, VARSTRING, STRING | string | |
|
||||
| TINY TEXT, MEDIUM TEXT, TEXT, LONG TEXT | string | |
|
||||
| TINY BLOB, MEDIUM BLOB, BLOG, LONG BLOB | string | BLOB Types are alias for TEXT types |
|
||||
| JSON | object/array | Automatically parsed |
|
||||
| BIT(1) | boolean | BIT(1) in MySQL |
|
||||
| GEOMETRY | string | Geometry data |
|
||||
|
||||
#### Differences from PostgreSQL
|
||||
|
||||
While the API is unified, there are some behavioral differences:
|
||||
|
||||
1. **Parameter placeholders**: MySQL uses `?` internally but Bun converts `$1, $2` style automatically
|
||||
2. **RETURNING clause**: MySQL doesn't support RETURNING; use `result.lastInsertRowid` or a separate SELECT
|
||||
3. **Array types**: MySQL doesn't have native array types like PostgreSQL
|
||||
|
||||
### MySQL-Specific Features
|
||||
|
||||
We haven't implemented `LOAD DATA INFILE` support yet
|
||||
|
||||
### PostgreSQL-Specific Features
|
||||
### Postgres-specific features
|
||||
|
||||
We haven't implemented these yet:
|
||||
|
||||
@@ -1262,89 +998,13 @@ We also haven't implemented some of the more uncommon features like:
|
||||
- Point & PostGIS types
|
||||
- All the multi-dimensional integer array types (only a couple of the types are supported)
|
||||
|
||||
## Common Patterns & Best Practices
|
||||
|
||||
### Working with MySQL Result Sets
|
||||
|
||||
```ts
|
||||
// Getting insert ID after INSERT
|
||||
const result = await mysql`INSERT INTO users (name) VALUES (${"Alice"})`;
|
||||
console.log(result.lastInsertRowid); // MySQL's LAST_INSERT_ID()
|
||||
|
||||
// Handling affected rows
|
||||
const updated =
|
||||
await mysql`UPDATE users SET active = ${false} WHERE age < ${18}`;
|
||||
console.log(updated.affectedRows); // Number of rows updated
|
||||
|
||||
// Using MySQL-specific functions
|
||||
const now = await mysql`SELECT NOW() as current_time`;
|
||||
const uuid = await mysql`SELECT UUID() as id`;
|
||||
```
|
||||
|
||||
### MySQL Error Handling
|
||||
|
||||
```ts
|
||||
try {
|
||||
await mysql`INSERT INTO users (email) VALUES (${"duplicate@email.com"})`;
|
||||
} catch (error) {
|
||||
if (error.code === "ER_DUP_ENTRY") {
|
||||
console.log("Duplicate entry detected");
|
||||
} else if (error.code === "ER_ACCESS_DENIED_ERROR") {
|
||||
console.log("Access denied");
|
||||
} else if (error.code === "ER_BAD_DB_ERROR") {
|
||||
console.log("Database does not exist");
|
||||
}
|
||||
// MySQL error codes are compatible with mysql/mysql2 packages
|
||||
}
|
||||
```
|
||||
|
||||
### Performance Tips for MySQL
|
||||
|
||||
1. **Use connection pooling**: Set appropriate `max` pool size based on your workload
|
||||
2. **Enable prepared statements**: They're enabled by default and improve performance
|
||||
3. **Use transactions for bulk operations**: Group related queries in transactions
|
||||
4. **Index properly**: MySQL relies heavily on indexes for query performance
|
||||
5. **Use `utf8mb4` charset**: It's set by default and handles all Unicode characters
|
||||
|
||||
## Frequently Asked Questions
|
||||
|
||||
> Why is this `Bun.sql` and not `Bun.postgres`?
|
||||
|
||||
The plan was to add more database drivers in the future. Now with MySQL support added, this unified API supports PostgreSQL, MySQL, and SQLite.
|
||||
The plan is to add more database drivers in the future.
|
||||
|
||||
> How do I know which database adapter is being used?
|
||||
|
||||
The adapter is automatically detected from the connection string:
|
||||
|
||||
- URLs starting with `mysql://` or `mysql2://` use MySQL
|
||||
- URLs matching SQLite patterns (`:memory:`, `sqlite://`, `file://`) use SQLite
|
||||
- Everything else defaults to PostgreSQL
|
||||
|
||||
> Are MySQL stored procedures supported?
|
||||
|
||||
Yes, stored procedures are fully supported including OUT parameters and multiple result sets:
|
||||
|
||||
```ts
|
||||
// Call stored procedure
|
||||
const results = await mysql`CALL GetUserStats(${userId}, @total_orders)`;
|
||||
|
||||
// Get OUT parameter
|
||||
const outParam = await mysql`SELECT @total_orders as total`;
|
||||
```
|
||||
|
||||
> Can I use MySQL-specific SQL syntax?
|
||||
|
||||
Yes, you can use any MySQL-specific syntax:
|
||||
|
||||
```ts
|
||||
// MySQL-specific syntax works fine
|
||||
await mysql`SET @user_id = ${userId}`;
|
||||
await mysql`SHOW TABLES`;
|
||||
await mysql`DESCRIBE users`;
|
||||
await mysql`EXPLAIN SELECT * FROM users WHERE id = ${id}`;
|
||||
```
|
||||
|
||||
## Why not just use an existing library?
|
||||
> Why not just use an existing library?
|
||||
|
||||
npm packages like postgres.js, pg, and node-postgres can be used in Bun too. They're great options.
|
||||
|
||||
|
||||
@@ -122,59 +122,6 @@ Messages are automatically enqueued until the worker is ready, so there is no ne
|
||||
|
||||
To send messages, use [`worker.postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage) and [`self.postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage). This leverages the [HTML Structured Clone Algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm).
|
||||
|
||||
### Performance optimizations
|
||||
|
||||
Bun includes optimized fast paths for `postMessage` to dramatically improve performance for common data types:
|
||||
|
||||
**String fast path** - When posting pure string values, Bun bypasses the structured clone algorithm entirely, achieving significant performance gains with no serialization overhead.
|
||||
|
||||
**Simple object fast path** - For plain objects containing only primitive values (strings, numbers, booleans, null, undefined), Bun uses an optimized serialization path that stores properties directly without full structured cloning.
|
||||
|
||||
The simple object fast path activates when the object:
|
||||
|
||||
- Is a plain object with no prototype chain modifications
|
||||
- Contains only enumerable, configurable data properties
|
||||
- Has no indexed properties or getter/setter methods
|
||||
- All property values are primitives or strings
|
||||
|
||||
With these fast paths, Bun's `postMessage` performs **2-241x faster** because the message length no longer has a meaningful impact on performance.
|
||||
|
||||
**Bun (with fast paths):**
|
||||
|
||||
```
|
||||
postMessage({ prop: 11 chars string, ...9 more props }) - 648ns
|
||||
postMessage({ prop: 14 KB string, ...9 more props }) - 719ns
|
||||
postMessage({ prop: 3 MB string, ...9 more props }) - 1.26µs
|
||||
```
|
||||
|
||||
**Node.js v24.6.0 (for comparison):**
|
||||
|
||||
```
|
||||
postMessage({ prop: 11 chars string, ...9 more props }) - 1.19µs
|
||||
postMessage({ prop: 14 KB string, ...9 more props }) - 2.69µs
|
||||
postMessage({ prop: 3 MB string, ...9 more props }) - 304µs
|
||||
```
|
||||
|
||||
```js
|
||||
// String fast path - optimized
|
||||
postMessage("Hello, worker!");
|
||||
|
||||
// Simple object fast path - optimized
|
||||
postMessage({
|
||||
message: "Hello",
|
||||
count: 42,
|
||||
enabled: true,
|
||||
data: null,
|
||||
});
|
||||
|
||||
// Complex objects still work but use standard structured clone
|
||||
postMessage({
|
||||
nested: { deep: { object: true } },
|
||||
date: new Date(),
|
||||
buffer: new ArrayBuffer(8),
|
||||
});
|
||||
```
|
||||
|
||||
```js
|
||||
// On the worker thread, `postMessage` is automatically "routed" to the parent thread.
|
||||
postMessage({ hello: "world" });
|
||||
|
||||
668
docs/api/yaml.md
668
docs/api/yaml.md
@@ -1,668 +0,0 @@
|
||||
In Bun, YAML is a first-class citizen alongside JSON and TOML.
|
||||
|
||||
Bun provides built-in support for YAML files through both runtime APIs and bundler integration. You can
|
||||
|
||||
- Parse YAML strings with `Bun.YAML.parse`
|
||||
- Stringify JavaScript objects to YAML with `Bun.YAML.stringify`
|
||||
- import & require YAML files as modules at runtime (including hot reloading & watch mode support)
|
||||
- import & require YAML files in frontend apps via bun's bundler
|
||||
|
||||
## Conformance
|
||||
|
||||
Bun's YAML parser currently passes over 90% of the official YAML test suite. While we're actively working on reaching 100% conformance, the current implementation covers the vast majority of real-world use cases. The parser is written in Zig for optimal performance and is continuously being improved.
|
||||
|
||||
## Runtime API
|
||||
|
||||
### `Bun.YAML.parse()`
|
||||
|
||||
Parse a YAML string into a JavaScript object.
|
||||
|
||||
```ts
|
||||
import { YAML } from "bun";
|
||||
const text = `
|
||||
name: John Doe
|
||||
age: 30
|
||||
email: john@example.com
|
||||
hobbies:
|
||||
- reading
|
||||
- coding
|
||||
- hiking
|
||||
`;
|
||||
|
||||
const data = YAML.parse(text);
|
||||
console.log(data);
|
||||
// {
|
||||
// name: "John Doe",
|
||||
// age: 30,
|
||||
// email: "john@example.com",
|
||||
// hobbies: ["reading", "coding", "hiking"]
|
||||
// }
|
||||
```
|
||||
|
||||
#### Multi-document YAML
|
||||
|
||||
When parsing YAML with multiple documents (separated by `---`), `Bun.YAML.parse()` returns an array:
|
||||
|
||||
```ts
|
||||
const multiDoc = `
|
||||
---
|
||||
name: Document 1
|
||||
---
|
||||
name: Document 2
|
||||
---
|
||||
name: Document 3
|
||||
`;
|
||||
|
||||
const docs = Bun.YAML.parse(multiDoc);
|
||||
console.log(docs);
|
||||
// [
|
||||
// { name: "Document 1" },
|
||||
// { name: "Document 2" },
|
||||
// { name: "Document 3" }
|
||||
// ]
|
||||
```
|
||||
|
||||
#### Supported YAML Features
|
||||
|
||||
Bun's YAML parser supports the full YAML 1.2 specification, including:
|
||||
|
||||
- **Scalars**: strings, numbers, booleans, null values
|
||||
- **Collections**: sequences (arrays) and mappings (objects)
|
||||
- **Anchors and Aliases**: reusable nodes with `&` and `*`
|
||||
- **Tags**: type hints like `!!str`, `!!int`, `!!float`, `!!bool`, `!!null`
|
||||
- **Multi-line strings**: literal (`|`) and folded (`>`) scalars
|
||||
- **Comments**: using `#`
|
||||
- **Directives**: `%YAML` and `%TAG`
|
||||
|
||||
```ts
|
||||
const yaml = `
|
||||
# Employee record
|
||||
employee: &emp
|
||||
name: Jane Smith
|
||||
department: Engineering
|
||||
skills:
|
||||
- JavaScript
|
||||
- TypeScript
|
||||
- React
|
||||
|
||||
manager: *emp # Reference to employee
|
||||
|
||||
config: !!str 123 # Explicit string type
|
||||
|
||||
description: |
|
||||
This is a multi-line
|
||||
literal string that preserves
|
||||
line breaks and spacing.
|
||||
|
||||
summary: >
|
||||
This is a folded string
|
||||
that joins lines with spaces
|
||||
unless there are blank lines.
|
||||
`;
|
||||
|
||||
const data = Bun.YAML.parse(yaml);
|
||||
```
|
||||
|
||||
#### Error Handling
|
||||
|
||||
`Bun.YAML.parse()` throws an error if the YAML is invalid:
|
||||
|
||||
```ts
|
||||
try {
|
||||
Bun.YAML.parse("invalid: yaml: content:");
|
||||
} catch (error) {
|
||||
console.error("Failed to parse YAML:", error.message);
|
||||
}
|
||||
```
|
||||
|
||||
### `Bun.YAML.stringify()`
|
||||
|
||||
Convert a JavaScript value into a YAML string. The API signature matches `JSON.stringify`:
|
||||
|
||||
```ts
|
||||
YAML.stringify(value, replacer?, space?)
|
||||
```
|
||||
|
||||
- `value`: The value to convert to YAML
|
||||
- `replacer`: Currently only `null` or `undefined` (function replacers not yet supported)
|
||||
- `space`: Number of spaces for indentation (e.g., `2`) or a string to use for indentation. **Without this parameter, outputs flow-style (single-line) YAML**
|
||||
|
||||
#### Basic Usage
|
||||
|
||||
```ts
|
||||
import { YAML } from "bun";
|
||||
|
||||
const data = {
|
||||
name: "John Doe",
|
||||
age: 30,
|
||||
hobbies: ["reading", "coding"],
|
||||
};
|
||||
|
||||
// Without space - outputs flow-style (single-line) YAML
|
||||
console.log(YAML.stringify(data));
|
||||
// {name: John Doe,age: 30,hobbies: [reading,coding]}
|
||||
|
||||
// With space=2 - outputs block-style (multi-line) YAML
|
||||
console.log(YAML.stringify(data, null, 2));
|
||||
// name: John Doe
|
||||
// age: 30
|
||||
// hobbies:
|
||||
// - reading
|
||||
// - coding
|
||||
```
|
||||
|
||||
#### Output Styles
|
||||
|
||||
```ts
|
||||
const arr = [1, 2, 3];
|
||||
|
||||
// Flow style (single-line) - default
|
||||
console.log(YAML.stringify(arr));
|
||||
// [1,2,3]
|
||||
|
||||
// Block style (multi-line) - with indentation
|
||||
console.log(YAML.stringify(arr, null, 2));
|
||||
// - 1
|
||||
// - 2
|
||||
// - 3
|
||||
```
|
||||
|
||||
#### String Quoting
|
||||
|
||||
`YAML.stringify()` automatically quotes strings when necessary:
|
||||
|
||||
- Strings that would be parsed as YAML keywords (`true`, `false`, `null`, `yes`, `no`, etc.)
|
||||
- Strings that would be parsed as numbers
|
||||
- Strings containing special characters or escape sequences
|
||||
|
||||
```ts
|
||||
const examples = {
|
||||
keyword: "true", // Will be quoted: "true"
|
||||
number: "123", // Will be quoted: "123"
|
||||
text: "hello world", // Won't be quoted: hello world
|
||||
empty: "", // Will be quoted: ""
|
||||
};
|
||||
|
||||
console.log(YAML.stringify(examples, null, 2));
|
||||
// keyword: "true"
|
||||
// number: "123"
|
||||
// text: hello world
|
||||
// empty: ""
|
||||
```
|
||||
|
||||
#### Cycles and References
|
||||
|
||||
`YAML.stringify()` automatically detects and handles circular references using YAML anchors and aliases:
|
||||
|
||||
```ts
|
||||
const obj = { name: "root" };
|
||||
obj.self = obj; // Circular reference
|
||||
|
||||
const yamlString = YAML.stringify(obj, null, 2);
|
||||
console.log(yamlString);
|
||||
// &root
|
||||
// name: root
|
||||
// self:
|
||||
// *root
|
||||
|
||||
// Objects with shared references
|
||||
const shared = { id: 1 };
|
||||
const data = {
|
||||
first: shared,
|
||||
second: shared,
|
||||
};
|
||||
|
||||
console.log(YAML.stringify(data, null, 2));
|
||||
// first:
|
||||
// &first
|
||||
// id: 1
|
||||
// second:
|
||||
// *first
|
||||
```
|
||||
|
||||
#### Special Values
|
||||
|
||||
```ts
|
||||
// Special numeric values
|
||||
console.log(YAML.stringify(Infinity)); // .inf
|
||||
console.log(YAML.stringify(-Infinity)); // -.inf
|
||||
console.log(YAML.stringify(NaN)); // .nan
|
||||
console.log(YAML.stringify(0)); // 0
|
||||
console.log(YAML.stringify(-0)); // -0
|
||||
|
||||
// null and undefined
|
||||
console.log(YAML.stringify(null)); // null
|
||||
console.log(YAML.stringify(undefined)); // undefined (returns undefined, not a string)
|
||||
|
||||
// Booleans
|
||||
console.log(YAML.stringify(true)); // true
|
||||
console.log(YAML.stringify(false)); // false
|
||||
```
|
||||
|
||||
#### Complex Objects
|
||||
|
||||
```ts
|
||||
const config = {
|
||||
server: {
|
||||
port: 3000,
|
||||
host: "localhost",
|
||||
ssl: {
|
||||
enabled: true,
|
||||
cert: "/path/to/cert.pem",
|
||||
key: "/path/to/key.pem",
|
||||
},
|
||||
},
|
||||
database: {
|
||||
connections: [
|
||||
{ name: "primary", host: "db1.example.com" },
|
||||
{ name: "replica", host: "db2.example.com" },
|
||||
],
|
||||
},
|
||||
features: {
|
||||
auth: true,
|
||||
"rate-limit": 100, // Keys with special characters are preserved
|
||||
},
|
||||
};
|
||||
|
||||
const yamlString = YAML.stringify(config, null, 2);
|
||||
console.log(yamlString);
|
||||
// server:
|
||||
// port: 3000
|
||||
// host: localhost
|
||||
// ssl:
|
||||
// enabled: true
|
||||
// cert: /path/to/cert.pem
|
||||
// key: /path/to/key.pem
|
||||
// database:
|
||||
// connections:
|
||||
// - name: primary
|
||||
// host: db1.example.com
|
||||
// - name: replica
|
||||
// host: db2.example.com
|
||||
// features:
|
||||
// auth: true
|
||||
// rate-limit: 100
|
||||
```
|
||||
|
||||
## Module Import
|
||||
|
||||
### ES Modules
|
||||
|
||||
You can import YAML files directly as ES modules. The YAML content is parsed and made available as both default and named exports:
|
||||
|
||||
```yaml#config.yaml
|
||||
database:
|
||||
host: localhost
|
||||
port: 5432
|
||||
name: myapp
|
||||
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
|
||||
features:
|
||||
auth: true
|
||||
rateLimit: true
|
||||
analytics: false
|
||||
```
|
||||
|
||||
#### Default Import
|
||||
|
||||
```ts#app.ts
|
||||
import config from "./config.yaml";
|
||||
|
||||
console.log(config.database.host); // "localhost"
|
||||
console.log(config.redis.port); // 6379
|
||||
```
|
||||
|
||||
#### Named Imports
|
||||
|
||||
You can destructure top-level YAML properties as named imports:
|
||||
|
||||
```ts
|
||||
import { database, redis, features } from "./config.yaml";
|
||||
|
||||
console.log(database.host); // "localhost"
|
||||
console.log(redis.port); // 6379
|
||||
console.log(features.auth); // true
|
||||
```
|
||||
|
||||
Or combine both:
|
||||
|
||||
```ts
|
||||
import config, { database, features } from "./config.yaml";
|
||||
|
||||
// Use the full config object
|
||||
console.log(config);
|
||||
|
||||
// Or use specific parts
|
||||
if (features.rateLimit) {
|
||||
setupRateLimiting(database);
|
||||
}
|
||||
```
|
||||
|
||||
### CommonJS
|
||||
|
||||
YAML files can also be required in CommonJS:
|
||||
|
||||
```js
|
||||
const config = require("./config.yaml");
|
||||
console.log(config.database.name); // "myapp"
|
||||
|
||||
// Destructuring also works
|
||||
const { database, redis } = require("./config.yaml");
|
||||
console.log(database.port); // 5432
|
||||
```
|
||||
|
||||
### TypeScript Support
|
||||
|
||||
While Bun can import YAML files directly, TypeScript doesn't know the types of your YAML files by default. To add TypeScript support for your YAML imports, create a declaration file with `.d.ts` appended to the YAML filename (e.g., `config.yaml` → `config.yaml.d.ts`):
|
||||
|
||||
```yaml#config.yaml
|
||||
features: "advanced"
|
||||
server:
|
||||
host: localhost
|
||||
port: 3000
|
||||
```
|
||||
|
||||
```ts#config.yaml.d.ts
|
||||
const contents: {
|
||||
features: string;
|
||||
server: {
|
||||
host: string;
|
||||
port: number;
|
||||
};
|
||||
};
|
||||
|
||||
export = contents;
|
||||
```
|
||||
|
||||
Now TypeScript will provide proper type checking and auto-completion:
|
||||
|
||||
```ts#app.ts
|
||||
import config from "./config.yaml";
|
||||
|
||||
// TypeScript knows the types!
|
||||
config.server.port; // number
|
||||
config.server.host; // string
|
||||
config.features; // string
|
||||
|
||||
// TypeScript will catch errors
|
||||
config.server.unknown; // Error: Property 'unknown' does not exist
|
||||
```
|
||||
|
||||
This approach works for both ES modules and CommonJS, giving you full type safety while Bun continues to handle the actual YAML parsing at runtime.
|
||||
|
||||
## Hot Reloading with YAML
|
||||
|
||||
One of the most powerful features of Bun's YAML support is hot reloading. When you run your application with `bun --hot`, changes to YAML files are automatically detected and reloaded without closing connections
|
||||
|
||||
### Configuration Hot Reloading
|
||||
|
||||
```yaml#config.yaml
|
||||
server:
|
||||
port: 3000
|
||||
host: localhost
|
||||
|
||||
features:
|
||||
debug: true
|
||||
verbose: false
|
||||
```
|
||||
|
||||
```ts#server.ts
|
||||
import { server, features } from "./config.yaml";
|
||||
|
||||
console.log(`Starting server on ${server.host}:${server.port}`);
|
||||
|
||||
if (features.debug) {
|
||||
console.log("Debug mode enabled");
|
||||
}
|
||||
|
||||
// Your server code here
|
||||
Bun.serve({
|
||||
port: server.port,
|
||||
hostname: server.host,
|
||||
fetch(req) {
|
||||
if (features.verbose) {
|
||||
console.log(`${req.method} ${req.url}`);
|
||||
}
|
||||
return new Response("Hello World");
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Run with hot reloading:
|
||||
|
||||
```bash
|
||||
bun --hot server.ts
|
||||
```
|
||||
|
||||
Now when you modify `config.yaml`, the changes are immediately reflected in your running application. This is perfect for:
|
||||
|
||||
- Adjusting configuration during development
|
||||
- Testing different settings without restarts
|
||||
- Live debugging with configuration changes
|
||||
- Feature flag toggling
|
||||
|
||||
## Configuration Management
|
||||
|
||||
### Environment-Based Configuration
|
||||
|
||||
YAML excels at managing configuration across different environments:
|
||||
|
||||
```yaml#config.yaml
|
||||
defaults: &defaults
|
||||
timeout: 5000
|
||||
retries: 3
|
||||
cache:
|
||||
enabled: true
|
||||
ttl: 3600
|
||||
|
||||
development:
|
||||
<<: *defaults
|
||||
api:
|
||||
url: http://localhost:4000
|
||||
key: dev_key_12345
|
||||
logging:
|
||||
level: debug
|
||||
pretty: true
|
||||
|
||||
staging:
|
||||
<<: *defaults
|
||||
api:
|
||||
url: https://staging-api.example.com
|
||||
key: ${STAGING_API_KEY}
|
||||
logging:
|
||||
level: info
|
||||
pretty: false
|
||||
|
||||
production:
|
||||
<<: *defaults
|
||||
api:
|
||||
url: https://api.example.com
|
||||
key: ${PROD_API_KEY}
|
||||
cache:
|
||||
enabled: true
|
||||
ttl: 86400
|
||||
logging:
|
||||
level: error
|
||||
pretty: false
|
||||
```
|
||||
|
||||
```ts#app.ts
|
||||
import configs from "./config.yaml";
|
||||
|
||||
const env = process.env.NODE_ENV || "development";
|
||||
const config = configs[env];
|
||||
|
||||
// Environment variables in YAML values can be interpolated
|
||||
function interpolateEnvVars(obj: any): any {
|
||||
if (typeof obj === "string") {
|
||||
return obj.replace(/\${(\w+)}/g, (_, key) => process.env[key] || "");
|
||||
}
|
||||
if (typeof obj === "object") {
|
||||
for (const key in obj) {
|
||||
obj[key] = interpolateEnvVars(obj[key]);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
export default interpolateEnvVars(config);
|
||||
```
|
||||
|
||||
### Feature Flags Configuration
|
||||
|
||||
```yaml#features.yaml
|
||||
features:
|
||||
newDashboard:
|
||||
enabled: true
|
||||
rolloutPercentage: 50
|
||||
allowedUsers:
|
||||
- admin@example.com
|
||||
- beta@example.com
|
||||
|
||||
experimentalAPI:
|
||||
enabled: false
|
||||
endpoints:
|
||||
- /api/v2/experimental
|
||||
- /api/v2/beta
|
||||
|
||||
darkMode:
|
||||
enabled: true
|
||||
default: auto # auto, light, dark
|
||||
```
|
||||
|
||||
```ts#feature-flags.ts
|
||||
import { features } from "./features.yaml";
|
||||
|
||||
export function isFeatureEnabled(
|
||||
featureName: string,
|
||||
userEmail?: string,
|
||||
): boolean {
|
||||
const feature = features[featureName];
|
||||
|
||||
if (!feature?.enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check rollout percentage
|
||||
if (feature.rolloutPercentage < 100) {
|
||||
const hash = hashCode(userEmail || "anonymous");
|
||||
if (hash % 100 >= feature.rolloutPercentage) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check allowed users
|
||||
if (feature.allowedUsers && userEmail) {
|
||||
return feature.allowedUsers.includes(userEmail);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use with hot reloading to toggle features in real-time
|
||||
if (isFeatureEnabled("newDashboard", user.email)) {
|
||||
renderNewDashboard();
|
||||
} else {
|
||||
renderLegacyDashboard();
|
||||
}
|
||||
```
|
||||
|
||||
### Database Configuration
|
||||
|
||||
```yaml#database.yaml
|
||||
connections:
|
||||
primary:
|
||||
type: postgres
|
||||
host: ${DB_HOST:-localhost}
|
||||
port: ${DB_PORT:-5432}
|
||||
database: ${DB_NAME:-myapp}
|
||||
username: ${DB_USER:-postgres}
|
||||
password: ${DB_PASS}
|
||||
pool:
|
||||
min: 2
|
||||
max: 10
|
||||
idleTimeout: 30000
|
||||
|
||||
cache:
|
||||
type: redis
|
||||
host: ${REDIS_HOST:-localhost}
|
||||
port: ${REDIS_PORT:-6379}
|
||||
password: ${REDIS_PASS}
|
||||
db: 0
|
||||
|
||||
analytics:
|
||||
type: clickhouse
|
||||
host: ${ANALYTICS_HOST:-localhost}
|
||||
port: 8123
|
||||
database: analytics
|
||||
|
||||
migrations:
|
||||
autoRun: ${AUTO_MIGRATE:-false}
|
||||
directory: ./migrations
|
||||
|
||||
seeds:
|
||||
enabled: ${SEED_DB:-false}
|
||||
directory: ./seeds
|
||||
```
|
||||
|
||||
```ts#db.ts
|
||||
import { connections, migrations } from "./database.yaml";
|
||||
import { createConnection } from "./database-driver";
|
||||
|
||||
// Parse environment variables with defaults
|
||||
function parseConfig(config: any) {
|
||||
return JSON.parse(
|
||||
JSON.stringify(config).replace(
|
||||
/\${([^:-]+)(?::([^}]+))?}/g,
|
||||
(_, key, defaultValue) => process.env[key] || defaultValue || "",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const dbConfig = parseConfig(connections);
|
||||
|
||||
export const db = await createConnection(dbConfig.primary);
|
||||
export const cache = await createConnection(dbConfig.cache);
|
||||
export const analytics = await createConnection(dbConfig.analytics);
|
||||
|
||||
// Auto-run migrations if configured
|
||||
if (parseConfig(migrations).autoRun === "true") {
|
||||
await runMigrations(db, migrations.directory);
|
||||
}
|
||||
```
|
||||
|
||||
### Bundler Integration
|
||||
|
||||
When you import YAML files in your application and bundle it with Bun, the YAML is parsed at build time and included as a JavaScript module:
|
||||
|
||||
```bash
|
||||
bun build app.ts --outdir=dist
|
||||
```
|
||||
|
||||
This means:
|
||||
|
||||
- Zero runtime YAML parsing overhead in production
|
||||
- Smaller bundle sizes
|
||||
- Tree-shaking support for unused configuration (named imports)
|
||||
|
||||
### Dynamic Imports
|
||||
|
||||
YAML files can be dynamically imported, useful for loading configuration on demand:
|
||||
|
||||
```ts#Load configuration based on environment
|
||||
const env = process.env.NODE_ENV || "development";
|
||||
const config = await import(`./configs/${env}.yaml`);
|
||||
|
||||
// Load user-specific settings
|
||||
async function loadUserSettings(userId: string) {
|
||||
try {
|
||||
const settings = await import(`./users/${userId}/settings.yaml`);
|
||||
return settings.default;
|
||||
} catch {
|
||||
return await import("./users/default-settings.yaml");
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -408,119 +408,16 @@ $ bun build --compile --asset-naming="[name].[ext]" ./index.ts
|
||||
|
||||
To trim down the size of the executable a little, pass `--minify` to `bun build --compile`. This uses Bun's minifier to reduce the code size. Overall though, Bun's binary is still way too big and we need to make it smaller.
|
||||
|
||||
## Using Bun.build() API
|
||||
|
||||
You can also generate standalone executables using the `Bun.build()` JavaScript API. This is useful when you need programmatic control over the build process.
|
||||
|
||||
### Basic usage
|
||||
|
||||
```js
|
||||
await Bun.build({
|
||||
entrypoints: ["./app.ts"],
|
||||
outdir: "./dist",
|
||||
compile: {
|
||||
target: "bun-windows-x64",
|
||||
outfile: "myapp.exe",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Windows metadata with Bun.build()
|
||||
|
||||
When targeting Windows, you can specify metadata through the `windows` object:
|
||||
|
||||
```js
|
||||
await Bun.build({
|
||||
entrypoints: ["./app.ts"],
|
||||
outdir: "./dist",
|
||||
compile: {
|
||||
target: "bun-windows-x64",
|
||||
outfile: "myapp.exe",
|
||||
windows: {
|
||||
title: "My Application",
|
||||
publisher: "My Company Inc",
|
||||
version: "1.2.3.4",
|
||||
description: "A powerful application built with Bun",
|
||||
copyright: "© 2024 My Company Inc",
|
||||
hideConsole: false, // Set to true for GUI applications
|
||||
icon: "./icon.ico", // Path to icon file
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Cross-compilation with Bun.build()
|
||||
|
||||
You can cross-compile for different platforms:
|
||||
|
||||
```js
|
||||
// Build for multiple platforms
|
||||
const platforms = [
|
||||
{ target: "bun-windows-x64", outfile: "app-windows.exe" },
|
||||
{ target: "bun-linux-x64", outfile: "app-linux" },
|
||||
{ target: "bun-darwin-arm64", outfile: "app-macos" },
|
||||
];
|
||||
|
||||
for (const platform of platforms) {
|
||||
await Bun.build({
|
||||
entrypoints: ["./app.ts"],
|
||||
outdir: "./dist",
|
||||
compile: platform,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Windows-specific flags
|
||||
|
||||
When compiling a standalone executable for Windows, there are several platform-specific options that can be used to customize the generated `.exe` file:
|
||||
When compiling a standalone executable on Windows, there are two platform-specific options that can be used to customize metadata on the generated `.exe` file:
|
||||
|
||||
### Visual customization
|
||||
|
||||
- `--windows-icon=path/to/icon.ico` - Set the executable file icon
|
||||
- `--windows-hide-console` - Disable the background terminal window (useful for GUI applications)
|
||||
|
||||
### Metadata customization
|
||||
|
||||
You can embed version information and other metadata into your Windows executable:
|
||||
|
||||
- `--windows-title <STR>` - Set the product name (appears in file properties)
|
||||
- `--windows-publisher <STR>` - Set the company name
|
||||
- `--windows-version <STR>` - Set the version number (e.g. "1.2.3.4")
|
||||
- `--windows-description <STR>` - Set the file description
|
||||
- `--windows-copyright <STR>` - Set the copyright information
|
||||
|
||||
#### Example with all metadata flags:
|
||||
|
||||
```sh
|
||||
bun build --compile ./app.ts \
|
||||
--outfile myapp.exe \
|
||||
--windows-title "My Application" \
|
||||
--windows-publisher "My Company Inc" \
|
||||
--windows-version "1.2.3.4" \
|
||||
--windows-description "A powerful application built with Bun" \
|
||||
--windows-copyright "© 2024 My Company Inc"
|
||||
```
|
||||
|
||||
This metadata will be visible in Windows Explorer when viewing the file properties:
|
||||
|
||||
1. Right-click the executable in Windows Explorer
|
||||
2. Select "Properties"
|
||||
3. Go to the "Details" tab
|
||||
|
||||
#### Version string format
|
||||
|
||||
The `--windows-version` flag accepts version strings in the following formats:
|
||||
|
||||
- `"1"` - Will be normalized to "1.0.0.0"
|
||||
- `"1.2"` - Will be normalized to "1.2.0.0"
|
||||
- `"1.2.3"` - Will be normalized to "1.2.3.0"
|
||||
- `"1.2.3.4"` - Full version format
|
||||
|
||||
Each version component must be a number between 0 and 65535.
|
||||
- `--windows-icon=path/to/icon.ico` to customize the executable file icon.
|
||||
- `--windows-hide-console` to disable the background terminal, which can be used for applications that do not need a TTY.
|
||||
|
||||
{% callout %}
|
||||
|
||||
These flags currently cannot be used when cross-compiling because they depend on Windows APIs. They are only available when building on Windows itself.
|
||||
These flags currently cannot be used when cross-compiling because they depend on Windows APIs.
|
||||
|
||||
{% /callout %}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Bun's fast native bundler can be used via the `bun build` CLI command or the `Bun.build()` JavaScript API.
|
||||
Bun's fast native bundler is now in beta. It can be used via the `bun build` CLI command or the `Bun.build()` JavaScript API.
|
||||
|
||||
{% codetabs group="a" %}
|
||||
|
||||
@@ -733,10 +733,6 @@ Whether to enable minification. Default `false`.
|
||||
When targeting `bun`, identifiers will be minified by default.
|
||||
{% /callout %}
|
||||
|
||||
{% callout %}
|
||||
When `minify.syntax` is enabled, unused function and class expression names are removed unless `minify.keepNames` is set to `true` or `--keep-names` flag is used.
|
||||
{% /callout %}
|
||||
|
||||
To enable all minification options:
|
||||
|
||||
{% codetabs group="a" %}
|
||||
@@ -767,16 +763,12 @@ await Bun.build({
|
||||
whitespace: true,
|
||||
identifiers: true,
|
||||
syntax: true,
|
||||
keepNames: false, // default
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
```bash#CLI
|
||||
$ bun build ./index.tsx --outdir ./out --minify-whitespace --minify-identifiers --minify-syntax
|
||||
|
||||
# To preserve function and class names during minification:
|
||||
$ bun build ./index.tsx --outdir ./out --minify --keep-names
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
@@ -1267,33 +1259,6 @@ $ bun build ./index.tsx --outdir ./out --drop=console --drop=debugger --drop=any
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
### `throw`
|
||||
|
||||
Controls error handling behavior when the build fails. When set to `true` (default), the returned promise rejects with an `AggregateError`. When set to `false`, the promise resolves with a `BuildOutput` object where `success` is `false`.
|
||||
|
||||
```ts#JavaScript
|
||||
// Default behavior: throws on error
|
||||
try {
|
||||
await Bun.build({
|
||||
entrypoints: ['./index.tsx'],
|
||||
throw: true, // default
|
||||
});
|
||||
} catch (error) {
|
||||
// Handle AggregateError
|
||||
console.error("Build failed:", error);
|
||||
}
|
||||
|
||||
// Alternative: handle errors via success property
|
||||
const result = await Bun.build({
|
||||
entrypoints: ['./index.tsx'],
|
||||
throw: false,
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
console.error("Build failed with errors:", result.logs);
|
||||
}
|
||||
```
|
||||
|
||||
## Outputs
|
||||
|
||||
The `Bun.build` function returns a `Promise<BuildOutput>`, defined as:
|
||||
@@ -1561,7 +1526,6 @@ interface BuildConfig {
|
||||
whitespace?: boolean;
|
||||
syntax?: boolean;
|
||||
identifiers?: boolean;
|
||||
keepNames?: boolean;
|
||||
};
|
||||
/**
|
||||
* Ignore dead code elimination/tree-shaking annotations such as @__PURE__ and package.json
|
||||
@@ -1605,7 +1569,8 @@ interface BuildConfig {
|
||||
* When set to `true`, the returned promise rejects with an AggregateError when a build failure happens.
|
||||
* When set to `false`, the `success` property of the returned object will be `false` when a build failure happens.
|
||||
*
|
||||
* This defaults to `true`.
|
||||
* This defaults to `false` in Bun 1.1 and will change to `true` in Bun 1.2
|
||||
* as most usage of `Bun.build` forgets to check for errors.
|
||||
*/
|
||||
throw?: boolean;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The Bun bundler implements a set of default loaders out of the box. As a rule of thumb, the bundler and the runtime both support the same set of file types out of the box.
|
||||
|
||||
`.js` `.cjs` `.mjs` `.mts` `.cts` `.ts` `.tsx` `.jsx` `.toml` `.json` `.yaml` `.yml` `.txt` `.wasm` `.node` `.html`
|
||||
`.js` `.cjs` `.mjs` `.mts` `.cts` `.ts` `.tsx` `.jsx` `.toml` `.json` `.txt` `.wasm` `.node` `.html`
|
||||
|
||||
Bun uses the file extension to determine which built-in _loader_ should be used to parse the file. Every loader has a name, such as `js`, `tsx`, or `json`. These names are used when building [plugins](https://bun.com/docs/bundler/plugins) that extend Bun with custom loaders.
|
||||
|
||||
@@ -121,55 +121,6 @@ export default {
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
### `yaml`
|
||||
|
||||
**YAML loader**. Default for `.yaml` and `.yml`.
|
||||
|
||||
YAML files can be directly imported. Bun will parse them with its fast native YAML parser.
|
||||
|
||||
```ts
|
||||
import config from "./config.yaml";
|
||||
config.database.host; // => "localhost"
|
||||
|
||||
// via import attribute:
|
||||
// import myCustomYAML from './my.config' with {type: "yaml"};
|
||||
```
|
||||
|
||||
During bundling, the parsed YAML is inlined into the bundle as a JavaScript object.
|
||||
|
||||
```ts
|
||||
var config = {
|
||||
database: {
|
||||
host: "localhost",
|
||||
port: 5432,
|
||||
},
|
||||
// ...other fields
|
||||
};
|
||||
config.database.host;
|
||||
```
|
||||
|
||||
If a `.yaml` or `.yml` file is passed as an entrypoint, it will be converted to a `.js` module that `export default`s the parsed object.
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```yaml#Input
|
||||
name: John Doe
|
||||
age: 35
|
||||
email: johndoe@example.com
|
||||
```
|
||||
|
||||
```js#Output
|
||||
export default {
|
||||
name: "John Doe",
|
||||
age: 35,
|
||||
email: "johndoe@example.com"
|
||||
}
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
For more details on YAML support including the runtime API `Bun.YAML.parse()`, see the [YAML API documentation](/docs/api/yaml).
|
||||
|
||||
### `text`
|
||||
|
||||
**Text loader**. Default for `.txt`.
|
||||
|
||||
@@ -9,7 +9,6 @@ Plugins can register callbacks to be run at various points in the lifecycle of a
|
||||
- [`onStart()`](#onstart): Run once the bundler has started a bundle
|
||||
- [`onResolve()`](#onresolve): Run before a module is resolved
|
||||
- [`onLoad()`](#onload): Run before a module is loaded.
|
||||
- [`onEnd()`](#onend): Run after the bundle has completed
|
||||
- [`onBeforeParse()`](#onbeforeparse): Run zero-copy native addons in the parser thread before a file is parsed.
|
||||
|
||||
### Reference
|
||||
@@ -19,7 +18,6 @@ A rough overview of the types (please refer to Bun's `bun.d.ts` for the full typ
|
||||
```ts
|
||||
type PluginBuilder = {
|
||||
onStart(callback: () => void): void;
|
||||
onEnd(callback: (result: BuildOutput) => void | Promise<void>): void;
|
||||
onResolve: (
|
||||
args: { filter: RegExp; namespace?: string },
|
||||
callback: (args: { path: string; importer: string }) => {
|
||||
@@ -287,53 +285,6 @@ plugin({
|
||||
|
||||
Note that the `.defer()` function currently has the limitation that it can only be called once per `onLoad` callback.
|
||||
|
||||
### `onEnd`
|
||||
|
||||
```ts
|
||||
onEnd(callback: (result: BuildOutput) => void | Promise<void>): void;
|
||||
```
|
||||
|
||||
Registers a callback to be run when the bundler completes a bundle (whether successful or not).
|
||||
|
||||
The callback receives the `BuildOutput` object containing:
|
||||
|
||||
- `success`: boolean indicating if the build succeeded
|
||||
- `outputs`: array of generated build artifacts
|
||||
- `logs`: array of build messages (warnings, errors, etc.)
|
||||
|
||||
This is useful for post-processing, cleanup, notifications, or custom error handling.
|
||||
|
||||
```ts
|
||||
await Bun.build({
|
||||
entrypoints: ["./index.ts"],
|
||||
outdir: "./out",
|
||||
plugins: [
|
||||
{
|
||||
name: "onEnd example",
|
||||
setup(build) {
|
||||
build.onEnd(result => {
|
||||
if (result.success) {
|
||||
console.log(
|
||||
`✅ Build succeeded with ${result.outputs.length} outputs`,
|
||||
);
|
||||
} else {
|
||||
console.error(`❌ Build failed with ${result.logs.length} errors`);
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
The `onEnd` callbacks are called:
|
||||
|
||||
- **Before** the build promise resolves or rejects
|
||||
- **After** all bundling is complete
|
||||
- **In the order** they were registered
|
||||
|
||||
Multiple plugins can register `onEnd` callbacks, and they will all be called sequentially. If an `onEnd` callback returns a promise, the build will wait for it to resolve before continuing.
|
||||
|
||||
## Native plugins
|
||||
|
||||
One of the reasons why Bun's bundler is so fast is that it is written in native code and leverages multi-threading to load and parse modules in parallel.
|
||||
|
||||
@@ -245,8 +245,8 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
|
||||
---
|
||||
|
||||
- `--jsx-side-effects`
|
||||
- `--jsx-side-effects`
|
||||
- Controls whether JSX expressions are marked as `/* @__PURE__ */` for dead code elimination. Default is `false` (JSX marked as pure).
|
||||
- n/a
|
||||
- JSX is always assumed to be side-effect-free
|
||||
|
||||
---
|
||||
|
||||
@@ -617,7 +617,7 @@ In Bun's CLI, simple boolean flags like `--minify` do not accept an argument. Ot
|
||||
|
||||
- `jsxSideEffects`
|
||||
- `jsxSideEffects`
|
||||
- Controls whether JSX expressions are marked as pure for dead code elimination
|
||||
- Not supported in JS API, configure in `tsconfig.json`
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -230,15 +230,16 @@ $ bun install --backend copyfile
|
||||
|
||||
**`symlink`** is typically only used for `file:` dependencies (and eventually `link:`) internally. To prevent infinite loops, it skips symlinking the `node_modules` folder.
|
||||
|
||||
If you install with `--backend=symlink`, Node.js won't resolve node_modules of dependencies unless each dependency has its own node_modules folder or you pass `--preserve-symlinks` to `node` or `bun`. See [Node.js documentation on `--preserve-symlinks`](https://nodejs.org/api/cli.html#--preserve-symlinks).
|
||||
If you install with `--backend=symlink`, Node.js won't resolve node_modules of dependencies unless each dependency has its own node_modules folder or you pass `--preserve-symlinks` to `node`. See [Node.js documentation on `--preserve-symlinks`](https://nodejs.org/api/cli.html#--preserve-symlinks).
|
||||
|
||||
```bash
|
||||
$ rm -rf node_modules
|
||||
$ bun install --backend symlink
|
||||
$ bun --preserve-symlinks ./my-file.js
|
||||
$ node --preserve-symlinks ./my-file.js # https://nodejs.org/api/cli.html#--preserve-symlinks
|
||||
```
|
||||
|
||||
Bun's runtime does not currently expose an equivalent of `--preserve-symlinks`, though the code for it does exist.
|
||||
|
||||
## npm registry metadata
|
||||
|
||||
bun uses a binary format for caching NPM registry responses. This loads much faster than JSON and tends to be smaller on disk.
|
||||
|
||||
@@ -8,14 +8,6 @@ The `bun` CLI contains a Node.js-compatible package manager designed to be a dra
|
||||
|
||||
{% /callout %}
|
||||
|
||||
{% callout %}
|
||||
|
||||
**💾 Disk efficient** — Bun install stores all packages in a global cache (`~/.bun/install/cache/`) and creates hardlinks (Linux) or copy-on-write clones (macOS) to `node_modules`. This means duplicate packages across projects point to the same underlying data, taking up virtually no extra disk space.
|
||||
|
||||
For more details, see [Package manager > Global cache](https://bun.com/docs/install/cache).
|
||||
|
||||
{% /callout %}
|
||||
|
||||
{% details summary="For Linux users" %}
|
||||
The recommended minimum Linux Kernel version is 5.6. If you're on Linux kernel 5.1 - 5.5, `bun install` will work, but HTTP requests will be slow due to a lack of support for io_uring's `connect()` operation.
|
||||
|
||||
@@ -215,12 +207,6 @@ Isolated installs create a central package store in `node_modules/.bun/` with sy
|
||||
|
||||
For complete documentation on isolated installs, refer to [Package manager > Isolated installs](https://bun.com/docs/install/isolated).
|
||||
|
||||
## Disk efficiency
|
||||
|
||||
Bun uses a global cache at `~/.bun/install/cache/` to minimize disk usage. Packages are stored once and linked to `node_modules` using hardlinks (Linux/Windows) or copy-on-write (macOS), so duplicate packages across projects don't consume additional disk space.
|
||||
|
||||
For complete documentation refer to [Package manager > Global cache](https://bun.com/docs/install/cache).
|
||||
|
||||
## Configuration
|
||||
|
||||
The default behavior of `bun install` can be configured in `bunfig.toml`. The default values are shown below.
|
||||
|
||||
109
docs/cli/test.md
109
docs/cli/test.md
@@ -109,85 +109,6 @@ Use the `--timeout` flag to specify a _per-test_ timeout in milliseconds. If a t
|
||||
$ bun test --timeout 20
|
||||
```
|
||||
|
||||
## Concurrent test execution
|
||||
|
||||
By default, Bun runs all tests sequentially within each test file. You can enable concurrent execution to run async tests in parallel, significantly speeding up test suites with independent tests.
|
||||
|
||||
### `--concurrent` flag
|
||||
|
||||
Use the `--concurrent` flag to run all tests concurrently within their respective files:
|
||||
|
||||
```sh
|
||||
$ bun test --concurrent
|
||||
```
|
||||
|
||||
When this flag is enabled, all tests will run in parallel unless explicitly marked with `test.serial`.
|
||||
|
||||
### `--max-concurrency` flag
|
||||
|
||||
Control the maximum number of tests running simultaneously with the `--max-concurrency` flag:
|
||||
|
||||
```sh
|
||||
# Limit to 4 concurrent tests
|
||||
$ bun test --concurrent --max-concurrency 4
|
||||
|
||||
# Default: 20
|
||||
$ bun test --concurrent
|
||||
```
|
||||
|
||||
This helps prevent resource exhaustion when running many concurrent tests. The default value is 20.
|
||||
|
||||
### `test.concurrent`
|
||||
|
||||
Mark individual tests to run concurrently, even when the `--concurrent` flag is not used:
|
||||
|
||||
```ts
|
||||
import { test, expect } from "bun:test";
|
||||
|
||||
// These tests run in parallel with each other
|
||||
test.concurrent("concurrent test 1", async () => {
|
||||
await fetch("/api/endpoint1");
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
test.concurrent("concurrent test 2", async () => {
|
||||
await fetch("/api/endpoint2");
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
// This test runs sequentially
|
||||
test("sequential test", () => {
|
||||
expect(1 + 1).toBe(2);
|
||||
});
|
||||
```
|
||||
|
||||
### `test.serial`
|
||||
|
||||
Force tests to run sequentially, even when the `--concurrent` flag is enabled:
|
||||
|
||||
```ts
|
||||
import { test, expect } from "bun:test";
|
||||
|
||||
let sharedState = 0;
|
||||
|
||||
// These tests must run in order
|
||||
test.serial("first serial test", () => {
|
||||
sharedState = 1;
|
||||
expect(sharedState).toBe(1);
|
||||
});
|
||||
|
||||
test.serial("second serial test", () => {
|
||||
// Depends on the previous test
|
||||
expect(sharedState).toBe(1);
|
||||
sharedState = 2;
|
||||
});
|
||||
|
||||
// This test can run concurrently if --concurrent is enabled
|
||||
test("independent test", () => {
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
```
|
||||
|
||||
## Rerun tests
|
||||
|
||||
Use the `--rerun-each` flag to run each test multiple times. This is useful for detecting flaky or non-deterministic test failures.
|
||||
@@ -196,36 +117,6 @@ Use the `--rerun-each` flag to run each test multiple times. This is useful for
|
||||
$ bun test --rerun-each 100
|
||||
```
|
||||
|
||||
## Randomize test execution order
|
||||
|
||||
Use the `--randomize` flag to run tests in a random order. This helps detect tests that depend on shared state or execution order.
|
||||
|
||||
```sh
|
||||
$ bun test --randomize
|
||||
```
|
||||
|
||||
When using `--randomize`, the seed used for randomization will be displayed in the test summary:
|
||||
|
||||
```sh
|
||||
$ bun test --randomize
|
||||
# ... test output ...
|
||||
--seed=12345
|
||||
2 pass
|
||||
8 fail
|
||||
Ran 10 tests across 2 files. [50.00ms]
|
||||
```
|
||||
|
||||
### Reproducible random order with `--seed`
|
||||
|
||||
Use the `--seed` flag to specify a seed for the randomization. This allows you to reproduce the same test order when debugging order-dependent failures.
|
||||
|
||||
```sh
|
||||
# Reproduce a previous randomized run
|
||||
$ bun test --seed 123456
|
||||
```
|
||||
|
||||
The `--seed` flag implies `--randomize`, so you don't need to specify both. Using the same seed value will always produce the same test execution order, making it easier to debug intermittent failures caused by test interdependencies.
|
||||
|
||||
## Bail out with `--bail`
|
||||
|
||||
Use the `--bail` flag to abort the test run early after a pre-determined number of test failures. By default Bun will run all tests and report all failures, but sometimes in CI environments it's preferable to terminate earlier to reduce CPU usage.
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "Deployment",
|
||||
"description": "A collection of guides for deploying Bun to providers"
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
---
|
||||
name: Deploy a Bun application on Railway
|
||||
description: Deploy Bun applications to Railway with this step-by-step guide covering CLI and dashboard methods, optional PostgreSQL setup, and automatic SSL configuration.
|
||||
---
|
||||
|
||||
Railway is an infrastructure platform where you can provision infrastructure, develop with that infrastructure locally, and then deploy to the cloud. It enables instant deployments from GitHub with zero configuration, automatic SSL, and built-in database provisioning.
|
||||
|
||||
This guide walks through deploying a Bun application with a PostgreSQL database (optional), which is exactly what the template below provides.
|
||||
|
||||
You can either follow this guide step-by-step or simply deploy the pre-configured template with one click:
|
||||
|
||||
{% raw %}
|
||||
|
||||
<a href="https://railway.com/deploy/bun-react-postgres?referralCode=Bun&utm_medium=integration&utm_source=template&utm_campaign=bun" target="_blank">
|
||||
<img src="https://railway.com/button.svg" alt="Deploy on Railway" />
|
||||
</a>
|
||||
|
||||
{% /raw %}
|
||||
|
||||
---
|
||||
|
||||
**Prerequisites**:
|
||||
|
||||
- A Bun application ready for deployment
|
||||
- A [Railway account](https://railway.app/)
|
||||
- Railway CLI (for CLI deployment method)
|
||||
- A GitHub account (for Dashboard deployment method)
|
||||
|
||||
---
|
||||
|
||||
## Method 1: Deploy via CLI
|
||||
|
||||
---
|
||||
|
||||
#### Step 1
|
||||
|
||||
Ensure sure you have the Railway CLI installed.
|
||||
|
||||
```bash
|
||||
bun install -g @railway/cli
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Step 2
|
||||
|
||||
Log into your Railway account.
|
||||
|
||||
```bash
|
||||
railway login
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Step 3
|
||||
|
||||
After successfully authenticating, initialize a new project.
|
||||
|
||||
```bash
|
||||
# Initialize project
|
||||
bun-react-postgres$ railway init
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Step 4
|
||||
|
||||
After initializing the project, add a new database and service.
|
||||
|
||||
> **Note:** Step 4 is only necessary if your application uses a database. If you don't need PostgreSQL, skip to Step 5.
|
||||
|
||||
```bash
|
||||
# Add PostgreSQL database. Make sure to add this first!
|
||||
bun-react-postgres$ railway add --database postgres
|
||||
|
||||
# Add your application service.
|
||||
bun-react-postgres$ railway add --service bun-react-db --variables DATABASE_URL=\${{Postgres.DATABASE_URL}}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Step 5
|
||||
|
||||
After the services have been created and connected, deploy the application to Railway. By default, services are only accessible within Railway's private network. To make your app publicly accessible, you need to generate a public domain.
|
||||
|
||||
```bash
|
||||
# Deploy your application
|
||||
bun-nextjs-starter$ railway up
|
||||
|
||||
# Generate public domain
|
||||
bun-nextjs-starter$ railway domain
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Method 2: Deploy via Dashboard
|
||||
|
||||
---
|
||||
|
||||
#### Step 1
|
||||
|
||||
Create a new project
|
||||
|
||||
1. Go to [Railway Dashboard](http://railway.com/dashboard?utm_medium=integration&utm_source=docs&utm_campaign=bun)
|
||||
2. Click **"+ New"** → **"GitHub repo"**
|
||||
3. Choose your repository
|
||||
|
||||
---
|
||||
|
||||
#### Step 2
|
||||
|
||||
Add a PostgreSQL database, and connect this database to the service
|
||||
|
||||
> **Note:** Step 2 is only necessary if your application uses a database. If you don't need PostgreSQL, skip to Step 3.
|
||||
|
||||
1. Click **"+ New"** → **"Database"** → **"Add PostgreSQL"**
|
||||
2. After the database has been created, select your service (not the database)
|
||||
3. Go to **"Variables"** tab
|
||||
4. Click **"+ New Variable"** → **"Add Reference"**
|
||||
5. Select `DATABASE_URL` from postgres
|
||||
|
||||
---
|
||||
|
||||
#### Step 3
|
||||
|
||||
Generate a public domain
|
||||
|
||||
1. Select your service
|
||||
2. Go to **"Settings"** tab
|
||||
3. Under **"Networking"**, click **"Generate Domain"**
|
||||
|
||||
---
|
||||
|
||||
Your app is now live! Railway auto-deploys on every GitHub push.
|
||||
|
||||
---
|
||||
|
||||
## Configuration (Optional)
|
||||
|
||||
---
|
||||
|
||||
By default, Railway uses [Nixpacks](https://docs.railway.com/guides/build-configuration#nixpacks-options) to automatically detect and build your Bun application with zero configuration.
|
||||
|
||||
However, using the [Railpack](https://docs.railway.com/guides/build-configuration#railpack) application builder provides better Bun support, and will always support the latest version of Bun. The pre-configured templates use Railpack by default.
|
||||
|
||||
To enable Railpack in a custom project, add the following to your `railway.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://railway.com/railway.schema.json",
|
||||
"build": {
|
||||
"builder": "RAILPACK"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For more build configuration settings, check out the [Railway documentation](https://docs.railway.com/guides/build-configuration).
|
||||
@@ -9,9 +9,8 @@ $ bun create next-app
|
||||
✔ What is your project named? … my-app
|
||||
✔ Would you like to use TypeScript with this project? … No / Yes
|
||||
✔ Would you like to use ESLint with this project? … No / Yes
|
||||
✔ Would you like to use Tailwind CSS? ... No / Yes
|
||||
✔ Would you like to use `src/` directory with this project? … No / Yes
|
||||
✔ Would you like to use App Router? (recommended) ... No / Yes
|
||||
✔ Would you like to use experimental `app/` directory with this project? … No / Yes
|
||||
✔ What import alias would you like configured? … @/*
|
||||
Creating a new Next.js app in /path/to/my-app.
|
||||
```
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
---
|
||||
name: Import a YAML file
|
||||
---
|
||||
|
||||
Bun natively supports `.yaml` and `.yml` imports.
|
||||
|
||||
```yaml#config.yaml
|
||||
database:
|
||||
host: localhost
|
||||
port: 5432
|
||||
name: myapp
|
||||
|
||||
server:
|
||||
port: 3000
|
||||
timeout: 30
|
||||
|
||||
features:
|
||||
auth: true
|
||||
rateLimit: true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Import the file like any other source file.
|
||||
|
||||
```ts
|
||||
import config from "./config.yaml";
|
||||
|
||||
config.database.host; // => "localhost"
|
||||
config.server.port; // => 3000
|
||||
config.features.auth; // => true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
You can also use named imports to destructure top-level properties:
|
||||
|
||||
```ts
|
||||
import { database, server, features } from "./config.yaml";
|
||||
|
||||
console.log(database.name); // => "myapp"
|
||||
console.log(server.timeout); // => 30
|
||||
console.log(features.rateLimit); // => true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Bun also supports [Import Attributes](https://github.com/tc39/proposal-import-attributes) syntax:
|
||||
|
||||
```ts
|
||||
import config from "./config.yaml" with { type: "yaml" };
|
||||
|
||||
config.database.port; // => 5432
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
For parsing YAML strings at runtime, use `Bun.YAML.parse()`:
|
||||
|
||||
```ts
|
||||
const yamlString = `
|
||||
name: John Doe
|
||||
age: 30
|
||||
hobbies:
|
||||
- reading
|
||||
- coding
|
||||
`;
|
||||
|
||||
const data = Bun.YAML.parse(yamlString);
|
||||
console.log(data.name); // => "John Doe"
|
||||
console.log(data.hobbies); // => ["reading", "coding"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## TypeScript Support
|
||||
|
||||
To add TypeScript support for your YAML imports, create a declaration file with `.d.ts` appended to the YAML filename (e.g., `config.yaml` → `config.yaml.d.ts`);
|
||||
|
||||
```ts#config.yaml.d.ts
|
||||
const contents: {
|
||||
database: {
|
||||
host: string;
|
||||
port: number;
|
||||
name: string;
|
||||
};
|
||||
server: {
|
||||
port: number;
|
||||
timeout: number;
|
||||
};
|
||||
features: {
|
||||
auth: boolean;
|
||||
rateLimit: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export = contents;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See [Docs > API > YAML](https://bun.com/docs/api/yaml) for complete documentation on YAML support in Bun.
|
||||
@@ -17,7 +17,7 @@ Bun reads the following files automatically (listed in order of increasing prece
|
||||
|
||||
- `.env`
|
||||
- `.env.production`, `.env.development`, `.env.test` (depending on value of `NODE_ENV`)
|
||||
- `.env.local` (not loaded when `NODE_ENV=test`)
|
||||
- `.env.local`
|
||||
|
||||
```txt#.env
|
||||
FOO=hello
|
||||
|
||||
@@ -35,7 +35,7 @@ Add this directive to _just one file_ in your project, such as:
|
||||
- Any single `.ts` file that TypeScript includes in your compilation
|
||||
|
||||
```ts
|
||||
/// <reference types="bun-types/test-globals" />
|
||||
/// <reference types="bun/test-globals" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -48,12 +48,12 @@ This behavior is configurable with the `--backend` flag, which is respected by a
|
||||
- **`copyfile`**: The fallback used when any of the above fail. It is the slowest option. On macOS, it uses `fcopyfile()`; on Linux it uses `copy_file_range()`.
|
||||
- **`symlink`**: Currently used only `file:` (and eventually `link:`) dependencies. To prevent infinite loops, it skips symlinking the `node_modules` folder.
|
||||
|
||||
If you install with `--backend=symlink`, Node.js won't resolve node_modules of dependencies unless each dependency has its own `node_modules` folder or you pass `--preserve-symlinks` to `node` or `bun`. See [Node.js documentation on `--preserve-symlinks`](https://nodejs.org/api/cli.html#--preserve-symlinks).
|
||||
If you install with `--backend=symlink`, Node.js won't resolve node_modules of dependencies unless each dependency has its own `node_modules` folder or you pass `--preserve-symlinks` to `node`. See [Node.js documentation on `--preserve-symlinks`](https://nodejs.org/api/cli.html#--preserve-symlinks).
|
||||
|
||||
```bash
|
||||
$ bun install --backend symlink
|
||||
$ node --preserve-symlinks ./foo.js
|
||||
$ bun --preserve-symlinks ./foo.js
|
||||
```
|
||||
|
||||
Bun's runtime does not currently expose an equivalent of `--preserve-symlinks`.
|
||||
{% /details %}
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
Bun's package manager can scan packages for security vulnerabilities before installation, helping protect your applications from supply chain attacks and known vulnerabilities.
|
||||
|
||||
## Quick Start
|
||||
|
||||
Configure a security scanner in your `bunfig.toml`:
|
||||
|
||||
```toml
|
||||
[install.security]
|
||||
scanner = "@acme/bun-security-scanner"
|
||||
```
|
||||
|
||||
When configured, Bun will:
|
||||
|
||||
- Scan all packages before installation
|
||||
- Display security warnings and advisories
|
||||
- Cancel installation if critical vulnerabilities are found
|
||||
- Automatically disable auto-install for security
|
||||
|
||||
## How It Works
|
||||
|
||||
Security scanners analyze packages during `bun install`, `bun add`, and other package operations. They can detect:
|
||||
|
||||
- Known security vulnerabilities (CVEs)
|
||||
- Malicious packages
|
||||
- License compliance issues
|
||||
- ...and more!
|
||||
|
||||
### Security Levels
|
||||
|
||||
Scanners report issues at two severity levels:
|
||||
|
||||
- **`fatal`** - Installation stops immediately, exits with non-zero code
|
||||
- **`warn`** - In interactive terminals, prompts to continue; in CI, exits immediately
|
||||
|
||||
## Using Pre-built Scanners
|
||||
|
||||
Many security companies publish Bun security scanners as npm packages that you can install and use immediately.
|
||||
|
||||
### Installing a Scanner
|
||||
|
||||
Install a security scanner from npm:
|
||||
|
||||
```bash
|
||||
$ bun add -d @acme/bun-security-scanner
|
||||
```
|
||||
|
||||
> **Note:** Consult your security scanner's documentation for their specific package name and installation instructions. Most scanners will be installed with `bun add`.
|
||||
|
||||
### Configuring the Scanner
|
||||
|
||||
After installation, configure it in your `bunfig.toml`:
|
||||
|
||||
```toml
|
||||
[install.security]
|
||||
scanner = "@acme/bun-security-scanner"
|
||||
```
|
||||
|
||||
### Enterprise Configuration
|
||||
|
||||
Some enterprise scanners might support authentication and/or configuration through environment variables:
|
||||
|
||||
```bash
|
||||
# This might go in ~/.bashrc, for example
|
||||
export SECURITY_API_KEY="your-api-key"
|
||||
|
||||
# The scanner will now use these credentials automatically
|
||||
bun install
|
||||
```
|
||||
|
||||
Consult your security scanner's documentation to learn which environment variables to set and if any additional configuration is required.
|
||||
|
||||
### Authoring your own scanner
|
||||
|
||||
For a complete example with tests and CI setup, see the official template:
|
||||
[github.com/oven-sh/security-scanner-template](https://github.com/oven-sh/security-scanner-template)
|
||||
|
||||
## Related
|
||||
|
||||
- [Configuration (bunfig.toml)](/docs/runtime/bunfig#install-security-scanner)
|
||||
- [Package Manager](/docs/install)
|
||||
- [Security Scanner Template](https://github.com/oven-sh/security-scanner-template)
|
||||
11
docs/nav.ts
11
docs/nav.ts
@@ -219,9 +219,6 @@ export default {
|
||||
page("install/npmrc", ".npmrc support", {
|
||||
description: "Bun supports loading some configuration options from .npmrc",
|
||||
}),
|
||||
page("install/security-scanner-api", "Security Scanner API", {
|
||||
description: "Scan your project for vulnerabilities with Bun's security scanner API.",
|
||||
}),
|
||||
// page("install/utilities", "Utilities", {
|
||||
// description: "Use `bun pm` to introspect your global module cache or project dependency tree.",
|
||||
// }),
|
||||
@@ -359,7 +356,7 @@ export default {
|
||||
page("api/file-io", "File I/O", {
|
||||
description: `Read and write files fast with Bun's heavily optimized file system API.`,
|
||||
}), // "`Bun.write`"),
|
||||
page("api/redis", "Redis Client", {
|
||||
page("api/redis", "Redis client", {
|
||||
description: `Bun provides a fast, native Redis client with automatic command pipelining for better performance.`,
|
||||
}),
|
||||
page("api/import-meta", "import.meta", {
|
||||
@@ -386,9 +383,6 @@ export default {
|
||||
page("api/spawn", "Child processes", {
|
||||
description: `Spawn sync and async child processes with easily configurable input and output streams.`,
|
||||
}), // "`Bun.spawn`"),
|
||||
page("api/yaml", "YAML", {
|
||||
description: `Bun.YAML.parse(string) lets you parse YAML files in JavaScript`,
|
||||
}), // "`Bun.spawn`"),
|
||||
page("api/html-rewriter", "HTMLRewriter", {
|
||||
description: `Parse and transform HTML with Bun's native HTMLRewriter API, inspired by Cloudflare Workers.`,
|
||||
}), // "`HTMLRewriter`"),
|
||||
@@ -407,9 +401,6 @@ export default {
|
||||
page("api/cc", "C Compiler", {
|
||||
description: `Build & run native C from JavaScript with Bun's native C compiler API`,
|
||||
}), // "`bun:ffi`"),
|
||||
page("api/secrets", "Secrets", {
|
||||
description: `Store and retrieve sensitive credentials securely using the operating system's native credential storage APIs.`,
|
||||
}), // "`Bun.secrets`"),
|
||||
page("cli/test", "Testing", {
|
||||
description: `Bun's built-in test runner is fast and uses Jest-compatible syntax.`,
|
||||
}), // "`bun:test`"),
|
||||
|
||||
@@ -195,12 +195,12 @@ Click the link in the right column to jump to the associated documentation.
|
||||
---
|
||||
|
||||
- Parsing & Formatting
|
||||
- [`Bun.semver`](https://bun.com/docs/api/semver), `Bun.TOML.parse`, [`Bun.YAML.parse`](https://bun.com/docs/api/yaml), [`Bun.color`](https://bun.com/docs/api/color)
|
||||
- [`Bun.semver`](https://bun.com/docs/api/semver), `Bun.TOML.parse`, [`Bun.color`](https://bun.com/docs/api/color)
|
||||
|
||||
---
|
||||
|
||||
- Low-level / Internals
|
||||
- `Bun.mmap`, `Bun.gc`, `Bun.generateHeapSnapshot`, [`bun:jsc`](https://bun.com/reference/bun/jsc)
|
||||
- `Bun.mmap`, `Bun.gc`, `Bun.generateHeapSnapshot`, [`bun:jsc`](https://bun.com/docs/api/bun-jsc)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -94,7 +94,6 @@ Bun supports the following loaders:
|
||||
- `file`
|
||||
- `json`
|
||||
- `toml`
|
||||
- `yaml`
|
||||
- `wasm`
|
||||
- `napi`
|
||||
- `base64`
|
||||
@@ -232,23 +231,6 @@ Set path where coverage reports will be saved. Please notice, that it works only
|
||||
coverageDir = "path/to/somewhere" # default "coverage"
|
||||
```
|
||||
|
||||
### `test.concurrentTestGlob`
|
||||
|
||||
Specify a glob pattern to automatically run matching test files with concurrent test execution enabled. Test files matching this pattern will behave as if the `--concurrent` flag was passed, running all tests within those files concurrently.
|
||||
|
||||
```toml
|
||||
[test]
|
||||
concurrentTestGlob = "**/concurrent-*.test.ts"
|
||||
```
|
||||
|
||||
This is useful for:
|
||||
|
||||
- Gradually migrating test suites to concurrent execution
|
||||
- Running integration tests concurrently while keeping unit tests sequential
|
||||
- Separating fast concurrent tests from tests that require sequential execution
|
||||
|
||||
The `--concurrent` CLI flag will override this setting when specified.
|
||||
|
||||
## Package manager
|
||||
|
||||
Package management is a complex issue; to support a range of use cases, the behavior of `bun install` can be configured under the `[install]` section.
|
||||
@@ -514,32 +496,6 @@ Whether to generate a non-Bun lockfile alongside `bun.lock`. (A `bun.lock` will
|
||||
print = "yarn"
|
||||
```
|
||||
|
||||
### `install.security.scanner`
|
||||
|
||||
Configure a security scanner to scan packages for vulnerabilities before installation.
|
||||
|
||||
First, install a security scanner from npm:
|
||||
|
||||
```bash
|
||||
$ bun add -d @acme/bun-security-scanner
|
||||
```
|
||||
|
||||
Then configure it in your `bunfig.toml`:
|
||||
|
||||
```toml
|
||||
[install.security]
|
||||
scanner = "@acme/bun-security-scanner"
|
||||
```
|
||||
|
||||
When a security scanner is configured:
|
||||
|
||||
- Auto-install is automatically disabled for security
|
||||
- Packages are scanned before installation
|
||||
- Installation is cancelled if fatal issues are found
|
||||
- Security warnings are displayed during installation
|
||||
|
||||
Learn more about [using and writing security scanners](/docs/install/security-scanner-api).
|
||||
|
||||
### `install.linker`
|
||||
|
||||
Configure the default linker strategy. Default `"hoisted"`.
|
||||
|
||||
@@ -8,10 +8,6 @@ Bun reads the following files automatically (listed in order of increasing prece
|
||||
- `.env.production`, `.env.development`, `.env.test` (depending on value of `NODE_ENV`)
|
||||
- `.env.local`
|
||||
|
||||
{% callout %}
|
||||
**Note:** When `NODE_ENV=test`, `.env.local` is **not** loaded. This ensures consistent test environments across different executions by preventing local overrides during testing. This behavior matches popular frameworks like [Next.js](https://nextjs.org/docs/pages/guides/environment-variables#test-environment-variables) and [Create React App](https://create-react-app.dev/docs/adding-custom-environment-variables/#what-other-env-files-can-be-used).
|
||||
{% /callout %}
|
||||
|
||||
```txt#.env
|
||||
FOO=hello
|
||||
BAR=world
|
||||
|
||||
@@ -92,18 +92,15 @@ every file before execution. Its transpiler can directly run TypeScript and JSX
|
||||
|
||||
## JSX
|
||||
|
||||
## JSON, TOML, and YAML
|
||||
## JSON and TOML
|
||||
|
||||
Source files can import `*.json`, `*.toml`, or `*.yaml` files to load their contents as plain JavaScript objects.
|
||||
Source files can import a `*.json` or `*.toml` file to load its contents as a plain old JavaScript object.
|
||||
|
||||
```ts
|
||||
import pkg from "./package.json";
|
||||
import bunfig from "./bunfig.toml";
|
||||
import config from "./config.yaml";
|
||||
```
|
||||
|
||||
See the [YAML API documentation](/docs/api/yaml) for more details on YAML support.
|
||||
|
||||
## WASI
|
||||
|
||||
{% callout %}
|
||||
|
||||
@@ -246,65 +246,6 @@ The module from which the component factory function (`createElement`, `jsx`, `j
|
||||
|
||||
{% /table %}
|
||||
|
||||
### `jsxSideEffects`
|
||||
|
||||
By default, Bun marks JSX expressions as `/* @__PURE__ */` so they can be removed during bundling if they are unused (known as "dead code elimination" or "tree shaking"). Set `jsxSideEffects` to `true` to prevent this behavior.
|
||||
|
||||
{% table %}
|
||||
|
||||
- Compiler options
|
||||
- Transpiled output
|
||||
|
||||
---
|
||||
|
||||
- ```jsonc
|
||||
{
|
||||
"jsx": "react",
|
||||
// jsxSideEffects is false by default
|
||||
}
|
||||
```
|
||||
|
||||
- ```tsx
|
||||
// JSX expressions are marked as pure
|
||||
/* @__PURE__ */ React.createElement("div", null, "Hello");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
- ```jsonc
|
||||
{
|
||||
"jsx": "react",
|
||||
"jsxSideEffects": true,
|
||||
}
|
||||
```
|
||||
|
||||
- ```tsx
|
||||
// JSX expressions are not marked as pure
|
||||
React.createElement("div", null, "Hello");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
- ```jsonc
|
||||
{
|
||||
"jsx": "react-jsx",
|
||||
"jsxSideEffects": true,
|
||||
}
|
||||
```
|
||||
|
||||
- ```tsx
|
||||
// Automatic runtime also respects jsxSideEffects
|
||||
jsx("div", { children: "Hello" });
|
||||
```
|
||||
|
||||
{% /table %}
|
||||
|
||||
This option is also available as a CLI flag:
|
||||
|
||||
```bash
|
||||
$ bun build --jsx-side-effects
|
||||
```
|
||||
|
||||
### JSX pragma
|
||||
|
||||
All of these values can be set on a per-file basis using _pragmas_. A pragma is a special comment that sets a compiler option in a particular file.
|
||||
|
||||
@@ -52,18 +52,15 @@ Hello world!
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
## JSON, TOML, and YAML
|
||||
## JSON and TOML
|
||||
|
||||
JSON, TOML, and YAML files can be directly imported from a source file. The contents will be loaded and returned as a JavaScript object.
|
||||
JSON and TOML files can be directly imported from a source file. The contents will be loaded and returned as a JavaScript object.
|
||||
|
||||
```ts
|
||||
import pkg from "./package.json";
|
||||
import data from "./data.toml";
|
||||
import config from "./config.yaml";
|
||||
```
|
||||
|
||||
For more details on YAML support, see the [YAML API documentation](/docs/api/yaml).
|
||||
|
||||
## WASI
|
||||
|
||||
{% callout %}
|
||||
|
||||
@@ -46,25 +46,6 @@ smol = true # Reduce memory usage during test runs
|
||||
|
||||
This is equivalent to using the `--smol` flag on the command line.
|
||||
|
||||
### Test execution
|
||||
|
||||
#### concurrentTestGlob
|
||||
|
||||
Automatically run test files matching a glob pattern with concurrent test execution enabled. This is useful for gradually migrating test suites to concurrent execution or for running specific test types concurrently.
|
||||
|
||||
```toml
|
||||
[test]
|
||||
concurrentTestGlob = "**/concurrent-*.test.ts" # Run files matching this pattern concurrently
|
||||
```
|
||||
|
||||
Test files matching this pattern will behave as if the `--concurrent` flag was passed, running all tests within those files concurrently. This allows you to:
|
||||
|
||||
- Gradually migrate your test suite to concurrent execution
|
||||
- Run integration tests concurrently while keeping unit tests sequential
|
||||
- Separate fast concurrent tests from tests that require sequential execution
|
||||
|
||||
The `--concurrent` CLI flag will override this setting when specified, forcing all tests to run concurrently regardless of the glob pattern.
|
||||
|
||||
### Coverage options
|
||||
|
||||
In addition to the options documented in the [coverage documentation](./coverage.md), the following options are available:
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
# Concurrent Test Glob Example
|
||||
|
||||
This example demonstrates how to use the `concurrentTestGlob` option to selectively run tests concurrently based on file naming patterns.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```text
|
||||
my-project/
|
||||
├── bunfig.toml
|
||||
├── tests/
|
||||
│ ├── unit/
|
||||
│ │ ├── math.test.ts # Sequential
|
||||
│ │ └── utils.test.ts # Sequential
|
||||
│ └── integration/
|
||||
│ ├── concurrent-api.test.ts # Concurrent
|
||||
│ └── concurrent-database.test.ts # Concurrent
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### bunfig.toml
|
||||
|
||||
```toml
|
||||
[test]
|
||||
# Run all test files with "concurrent-" prefix concurrently
|
||||
concurrentTestGlob = "**/concurrent-*.test.ts"
|
||||
```
|
||||
|
||||
## Test Files
|
||||
|
||||
### Unit Test (Sequential)
|
||||
|
||||
`tests/unit/math.test.ts`
|
||||
|
||||
```typescript
|
||||
import { test, expect } from "bun:test";
|
||||
|
||||
// These tests run sequentially by default
|
||||
// Good for tests that share state or have specific ordering requirements
|
||||
let sharedState = 0;
|
||||
|
||||
test("addition", () => {
|
||||
sharedState = 5 + 3;
|
||||
expect(sharedState).toBe(8);
|
||||
});
|
||||
|
||||
test("uses previous state", () => {
|
||||
// This test depends on the previous test's state
|
||||
expect(sharedState).toBe(8);
|
||||
});
|
||||
```
|
||||
|
||||
### Integration Test (Concurrent)
|
||||
|
||||
`tests/integration/concurrent-api.test.ts`
|
||||
|
||||
```typescript
|
||||
import { test, expect } from "bun:test";
|
||||
|
||||
// These tests automatically run concurrently due to filename matching the glob pattern.
|
||||
// Using test() is equivalent to test.concurrent() when the file matches concurrentTestGlob.
|
||||
// Each test is independent and can run in parallel.
|
||||
|
||||
test("fetch user data", async () => {
|
||||
const response = await fetch("/api/user/1");
|
||||
expect(response.ok).toBe(true);
|
||||
});
|
||||
|
||||
test("fetch posts", async () => {
|
||||
const response = await fetch("/api/posts");
|
||||
expect(response.ok).toBe(true);
|
||||
});
|
||||
|
||||
test("fetch comments", async () => {
|
||||
const response = await fetch("/api/comments");
|
||||
expect(response.ok).toBe(true);
|
||||
});
|
||||
```
|
||||
|
||||
## Running Tests
|
||||
|
||||
```bash
|
||||
# Run all tests - concurrent-*.test.ts files will run concurrently
|
||||
bun test
|
||||
|
||||
# Override: Force ALL tests to run concurrently
|
||||
# Note: This overrides bunfig.toml and runs all tests concurrently, regardless of glob
|
||||
bun test --concurrent
|
||||
|
||||
# Run only unit tests (sequential)
|
||||
bun test tests/unit
|
||||
|
||||
# Run only integration tests (concurrent due to glob pattern)
|
||||
bun test tests/integration
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
1. **Gradual Migration**: Migrate to concurrent tests file by file by renaming them
|
||||
2. **Clear Organization**: File naming convention indicates execution mode
|
||||
3. **Performance**: Integration tests run faster in parallel
|
||||
4. **Safety**: Unit tests remain sequential where needed
|
||||
5. **Flexibility**: Easy to change execution mode by renaming files
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
To migrate existing tests to concurrent execution:
|
||||
|
||||
1. Start with independent integration tests
|
||||
2. Rename files to match the glob pattern: `mv api.test.ts concurrent-api.test.ts`
|
||||
3. Verify tests still pass
|
||||
4. Monitor for race conditions or shared state issues
|
||||
5. Continue migrating stable tests incrementally
|
||||
|
||||
## Tips
|
||||
|
||||
- Use descriptive prefixes: `concurrent-`, `parallel-`, `async-`
|
||||
- Keep related sequential tests together
|
||||
- Document why certain tests must remain sequential
|
||||
- Use `test.concurrent()` for fine-grained control in sequential files
|
||||
(In files matched by `concurrentTestGlob`, plain `test()` already runs concurrently)
|
||||
- Consider separate globs for different test types:
|
||||
|
||||
```toml
|
||||
[test]
|
||||
# Multiple patterns for different test categories
|
||||
concurrentTestGlob = [
|
||||
"**/integration/*.test.ts",
|
||||
"**/e2e/*.test.ts",
|
||||
"**/concurrent-*.test.ts"
|
||||
]
|
||||
```
|
||||
@@ -12,8 +12,6 @@ test("NODE_ENV is set to test", () => {
|
||||
});
|
||||
```
|
||||
|
||||
When `NODE_ENV` is set to `"test"`, Bun will not load `.env.local` files. This ensures consistent test environments across different executions by preventing local overrides during testing. Instead, use `.env.test` for test-specific environment variables, which should be committed to your repository for consistency across all developers and CI environments.
|
||||
|
||||
#### `$TZ` environment variable
|
||||
|
||||
By default, all `bun test` runs use UTC (`Etc/UTC`) as the time zone unless overridden by the `TZ` environment variable. This ensures consistent date and time behavior across different development environments.
|
||||
|
||||
@@ -149,6 +149,12 @@ describe.only("only", () => {
|
||||
|
||||
The following command will only execute tests #2 and #3.
|
||||
|
||||
```sh
|
||||
$ bun test --only
|
||||
```
|
||||
|
||||
The following command will only execute tests #1, #2 and #3.
|
||||
|
||||
```sh
|
||||
$ bun test
|
||||
```
|
||||
@@ -750,76 +756,3 @@ Bun implements the following matchers. Full Jest compatibility is on the roadmap
|
||||
- [`.toThrowErrorMatchingInlineSnapshot()`](https://jestjs.io/docs/expect#tothrowerrormatchinginlinesnapshotinlinesnapshot)
|
||||
|
||||
{% /table %}
|
||||
|
||||
## TypeScript Type Safety
|
||||
|
||||
Bun's test runner provides enhanced TypeScript support with intelligent type checking for your test assertions. The type system helps catch potential bugs at compile time while still allowing flexibility when needed.
|
||||
|
||||
### Strict Type Checking by Default
|
||||
|
||||
By default, Bun's test matchers enforce strict type checking between the actual value and expected value:
|
||||
|
||||
```ts
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
test("strict typing", () => {
|
||||
const str = "hello";
|
||||
const num = 42;
|
||||
|
||||
expect(str).toBe("hello"); // ✅ OK: string to string
|
||||
expect(num).toBe(42); // ✅ OK: number to number
|
||||
expect(str).toBe(42); // ❌ TypeScript error: string vs number
|
||||
});
|
||||
```
|
||||
|
||||
This helps catch common mistakes where you might accidentally compare values of different types.
|
||||
|
||||
### Relaxed Type Checking with Type Parameters
|
||||
|
||||
Sometimes you need more flexibility in your tests, especially when working with:
|
||||
|
||||
- Dynamic data from APIs
|
||||
- Polymorphic functions that can return multiple types
|
||||
- Generic utility functions
|
||||
- Migration of existing test suites
|
||||
|
||||
For these cases, you can "opt out" of strict type checking by providing an explicit type parameter to matcher methods:
|
||||
|
||||
```ts
|
||||
import { expect, test } from "bun:test";
|
||||
|
||||
test("relaxed typing with type parameters", () => {
|
||||
const value: unknown = getSomeValue();
|
||||
|
||||
// These would normally cause TypeScript errors, but type parameters allow them:
|
||||
expect(value).toBe<number>(42); // No TS error, runtime check still works
|
||||
expect(value).toEqual<string>("hello"); // No TS error, runtime check still works
|
||||
expect(value).toStrictEqual<boolean>(true); // No TS error, runtime check still works
|
||||
});
|
||||
|
||||
test("useful for dynamic data", () => {
|
||||
const apiResponse: any = { status: "success" };
|
||||
|
||||
// Without type parameter: TypeScript error (any vs string)
|
||||
// expect(apiResponse.status).toBe("success");
|
||||
|
||||
// With type parameter: No TypeScript error, runtime assertion still enforced
|
||||
expect(apiResponse.status).toBe<string>("success"); // ✅ OK
|
||||
});
|
||||
```
|
||||
|
||||
### Migration from Looser Type Systems
|
||||
|
||||
If migrating from a test framework with looser TypeScript integration, you can use type parameters as a stepping stone:
|
||||
|
||||
```ts
|
||||
// Old Jest test that worked but wasn't type-safe
|
||||
expect(response.data).toBe(200); // No type error in some setups
|
||||
|
||||
// Bun equivalent with explicit typing during migration
|
||||
expect(response.data).toBe<number>(200); // Explicit about expected type
|
||||
|
||||
// Ideal Bun test after refactoring
|
||||
const statusCode: number = response.data;
|
||||
expect(statusCode).toBe(200); // Type-safe without explicit parameter
|
||||
```
|
||||
|
||||
@@ -19,6 +19,3 @@ command script import -c bun_pretty_printer.py
|
||||
|
||||
command script delete btjs
|
||||
command alias btjs p {printf("gathering btjs trace...\n");printf("%s\n", (char*)dumpBtjsTrace())}
|
||||
|
||||
# do not pass SIGHUP on to child process. it is often not the real error and the stop point will be nonsensical.
|
||||
process handle -p false -s false -n true SIGHUP
|
||||
|
||||
11
package.json
11
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "bun",
|
||||
"version": "1.2.24",
|
||||
"version": "1.2.21",
|
||||
"workspaces": [
|
||||
"./packages/bun-types",
|
||||
"./packages/@types/bun"
|
||||
@@ -32,8 +32,8 @@
|
||||
"watch-windows": "bun run zig build check-windows --watch -fincremental --prominent-compile-errors --global-cache-dir build/debug/zig-check-cache --zig-lib-dir vendor/zig/lib",
|
||||
"bd:v": "(bun run --silent build:debug &> /tmp/bun.debug.build.log || (cat /tmp/bun.debug.build.log && rm -rf /tmp/bun.debug.build.log && exit 1)) && rm -f /tmp/bun.debug.build.log && ./build/debug/bun-debug",
|
||||
"bd": "BUN_DEBUG_QUIET_LOGS=1 bun --silent bd:v",
|
||||
"build:debug": "export COMSPEC=\"C:\\Windows\\System32\\cmd.exe\" && bun ./scripts/build.mjs -GNinja -DCMAKE_BUILD_TYPE=Debug -B build/debug --log-level=NOTICE",
|
||||
"build:debug:noasan": "export COMSPEC=\"C:\\Windows\\System32\\cmd.exe\" && bun ./scripts/build.mjs -GNinja -DCMAKE_BUILD_TYPE=Debug -DENABLE_ASAN=OFF -B build/debug --log-level=NOTICE",
|
||||
"build:debug": "export COMSPEC=\"C:\\Windows\\System32\\cmd.exe\" && bun scripts/glob-sources.mjs > /dev/null && bun ./scripts/build.mjs -GNinja -DCMAKE_BUILD_TYPE=Debug -B build/debug --log-level=NOTICE",
|
||||
"build:debug:asan": "bun ./scripts/build.mjs -GNinja -DCMAKE_BUILD_TYPE=Debug -DENABLE_ASAN=ON -B build/debug-asan --log-level=NOTICE",
|
||||
"build:release": "bun ./scripts/build.mjs -GNinja -DCMAKE_BUILD_TYPE=Release -B build/release",
|
||||
"build:ci": "bun ./scripts/build.mjs -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=ON -DCI=true -B build/release-ci --verbose --fresh",
|
||||
"build:assert": "bun ./scripts/build.mjs -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_ASSERTIONS=ON -DENABLE_LOGS=ON -B build/release-assert",
|
||||
@@ -84,11 +84,6 @@
|
||||
"node:test": "node ./scripts/runner.node.mjs --quiet --exec-path=$npm_execpath --node-tests ",
|
||||
"node:test:cp": "bun ./scripts/fetch-node-test.ts ",
|
||||
"clean:zig": "rm -rf build/debug/cache/zig build/debug/CMakeCache.txt 'build/debug/*.o' .zig-cache zig-out || true",
|
||||
"machine:linux:ubuntu": "./scripts/machine.mjs ssh --cloud=aws --arch=x64 --instance-type c7i.2xlarge --os=linux --distro=ubuntu --release=25.04",
|
||||
"machine:linux:debian": "./scripts/machine.mjs ssh --cloud=aws --arch=x64 --instance-type c7i.2xlarge --os=linux --distro=debian --release=12",
|
||||
"machine:linux:alpine": "./scripts/machine.mjs ssh --cloud=aws --arch=x64 --instance-type c7i.2xlarge --os=linux --distro=alpine --release=3.21",
|
||||
"machine:linux:amazonlinux": "./scripts/machine.mjs ssh --cloud=aws --arch=x64 --instance-type c7i.2xlarge --os=linux --distro=amazonlinux --release=2023",
|
||||
"machine:windows:2019": "./scripts/machine.mjs ssh --cloud=aws --arch=x64 --instance-type c7i.2xlarge --os=windows --release=2019",
|
||||
"sync-webkit-source": "bun ./scripts/sync-webkit-source.ts"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "bun-error",
|
||||
"dependencies": {
|
||||
"preact": "^10.27.2",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"preact": ["preact@10.27.2", "", {}, "sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg=="],
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { JSX } from "preact";
|
||||
import { createContext, render } from "preact";
|
||||
import { useCallback, useContext, useEffect, useRef, useState } from "preact/hooks";
|
||||
import React, { createContext, useContext } from "react";
|
||||
import { render, unmountComponentAtNode } from "react-dom";
|
||||
import type {
|
||||
FallbackMessageContainer,
|
||||
JSException,
|
||||
@@ -165,17 +164,17 @@ const maybeBlobFileURL = (filename: string, line?: number, column?: number): str
|
||||
return srcFileURL(filename, line, column);
|
||||
};
|
||||
|
||||
const openWithoutFlashOfNewTab: JSX.MouseEventHandler<HTMLAnchorElement> = event => {
|
||||
const target = event.currentTarget as HTMLAnchorElement;
|
||||
const openWithoutFlashOfNewTab: React.MouseEventHandler<HTMLAnchorElement> = event => {
|
||||
const target = event.currentTarget;
|
||||
const href = target.getAttribute("href");
|
||||
if (!href || event.button !== 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
event.stopImmediatePropagation();
|
||||
event.nativeEvent.preventDefault();
|
||||
event.nativeEvent.stopPropagation();
|
||||
event.nativeEvent.stopImmediatePropagation();
|
||||
|
||||
const headers = new Headers();
|
||||
headers.set("Accept", "text/plain");
|
||||
@@ -318,17 +317,17 @@ const AsyncSourceLines = ({
|
||||
highlight: number;
|
||||
highlightColumnStart: number;
|
||||
highlightColumnEnd: number;
|
||||
children?: any;
|
||||
children?: React.ReactNode;
|
||||
buildURL: (line?: number, column?: number) => string;
|
||||
sourceLines: SourceLine[];
|
||||
setSourceLines: (lines: SourceLine[]) => void;
|
||||
}) => {
|
||||
const [loadState, setLoadState] = useState(LoadState.pending);
|
||||
const [loadState, setLoadState] = React.useState(LoadState.pending);
|
||||
|
||||
const controller = useRef<AbortController | null>(null);
|
||||
const url = useRef<string>(buildURL(0, 0));
|
||||
const controller = React.useRef<AbortController | null>(null);
|
||||
const url = React.useRef<string>(buildURL(0, 0));
|
||||
|
||||
useEffect(() => {
|
||||
React.useEffect(() => {
|
||||
controller.current = new AbortController();
|
||||
var cancelled = false;
|
||||
fetch(url.current, {
|
||||
@@ -433,7 +432,7 @@ const SourceLines = ({
|
||||
highlight: number;
|
||||
highlightColumnStart: number;
|
||||
highlightColumnEnd: number;
|
||||
children?: any;
|
||||
children?: React.ReactNode;
|
||||
buildURL: (line?: number, column?: number) => string;
|
||||
}) => {
|
||||
let start = sourceLines.length;
|
||||
@@ -462,7 +461,7 @@ const SourceLines = ({
|
||||
const leftPad = maxLineNumber.toString(10).length - minLineNumber.toString(10).length;
|
||||
|
||||
const _sourceLines = sourceLines.slice(start, end);
|
||||
const lines = new Array(_sourceLines.length + (Array.isArray(children) ? children.length : children ? 1 : 0));
|
||||
const lines = new Array(_sourceLines.length + React.Children.count(children));
|
||||
|
||||
let highlightI = 0;
|
||||
for (let i = 0; i < _sourceLines.length; i++) {
|
||||
@@ -514,7 +513,7 @@ const SourceLines = ({
|
||||
const BuildErrorSourceLines = ({ location, filename }: { location: Location; filename: string }) => {
|
||||
const { line, line_text, column } = location;
|
||||
const sourceLines: SourceLine[] = [{ line, text: line_text }];
|
||||
const buildURL = useCallback((line, column) => srcFileURL(filename, line, column), [filename]);
|
||||
const buildURL = React.useCallback((line, column) => srcFileURL(filename, line, column), [srcFileURL, filename]);
|
||||
return (
|
||||
<SourceLines
|
||||
sourceLines={sourceLines}
|
||||
@@ -670,15 +669,15 @@ const NativeStackTrace = ({
|
||||
frames: StackFrame[];
|
||||
sourceLines: SourceLine[];
|
||||
setSourceLines: (sourceLines: SourceLine[]) => void;
|
||||
children?: any;
|
||||
children?: React.ReactNode;
|
||||
isClient: boolean;
|
||||
}) => {
|
||||
const { file = "", position } = frames[0];
|
||||
const { cwd } = useContext(ErrorGroupContext);
|
||||
const filename = normalizedFilename(file, cwd);
|
||||
const urlBuilder = isClient ? clientURL : maybeBlobFileURL;
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const buildURL = useCallback((line, column) => urlBuilder(file, line, column), [file, urlBuilder]);
|
||||
const ref = React.useRef<HTMLDivElement>(null);
|
||||
const buildURL = React.useCallback((line, column) => urlBuilder(file, line, column), [file, urlBuilder]);
|
||||
|
||||
return (
|
||||
<div ref={ref} className={`BunError-NativeStackTrace`}>
|
||||
@@ -733,7 +732,7 @@ const Indent = ({ by, children }) => {
|
||||
|
||||
const JSException = ({ value, isClient = false }: { value: JSExceptionType; isClient: boolean }) => {
|
||||
const tag = isClient ? ErrorTagType.client : ErrorTagType.server;
|
||||
const [sourceLines, _setSourceLines] = useState(value?.stack?.source_lines ?? []);
|
||||
const [sourceLines, _setSourceLines] = React.useState(value?.stack?.source_lines ?? []);
|
||||
var message = value.message || "";
|
||||
var name = value.name || "";
|
||||
if (!name && !message) {
|
||||
@@ -1243,7 +1242,7 @@ export function renderRuntimeError(error: Error) {
|
||||
|
||||
export function dismissError() {
|
||||
if (reactRoot) {
|
||||
render(null, reactRoot);
|
||||
unmountComponentAtNode(reactRoot);
|
||||
const root = document.getElementById("__bun__error-root");
|
||||
if (root) root.remove();
|
||||
reactRoot = null;
|
||||
|
||||
@@ -5,9 +5,14 @@
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "bun build --production --define:process.env.NODE_ENV=\"'production'\" --minify index.tsx bun-error.css --outdir=dist --target=browser --format=esm"
|
||||
"build": "esbuild --define:process.env.NODE_ENV=\"'production'\" --minify index.tsx bun-error.css --bundle --outdir=dist --platform=browser --format=esm"
|
||||
},
|
||||
"dependencies": {
|
||||
"preact": "^10.27.2"
|
||||
"esbuild": "latest",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^17.0.39"
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user