tauri-plugin-widgets 0.4.3

Tauri plugin for App Widgets on Android, iOS, and macOS (WidgetKit); Windows Widgets Board (Adaptive Cards) + desktop webview; Linux desktop webview with X11 DESKTOP pin.
Documentation
#Requires -Version 5.1
# Windows smoke + visual Adaptive Card capture.
param(
  [string]$Repo = "C:\work\tauri-plugin-widgets",
  [ValidateSet("smoke", "visual")]
  [string]$Mode = "smoke",
  [string]$Case = "",
  [switch]$Record,
  [switch]$SkipDotnet,
  [switch]$SkipCargo
)

$ErrorActionPreference = "Stop"
Set-Location $Repo

function Test-MsvcLinker {
  return $null -ne (Get-Command link.exe -ErrorAction SilentlyContinue)
}

function Ensure-PreviewHost {
  param(
    [bool]$FullRenderer = $false
  )
  $src = Join-Path $Repo "templates\windows-widget\PreviewHost"
  $smokeDir = Join-Path $env:TEMP ("tpw-previewhost-" + $(if ($FullRenderer) { "full" } else { "smoke" }))
  if (Test-Path $smokeDir) { Remove-Item -Recurse -Force $smokeDir }
  Copy-Item -Recurse $src $smokeDir
  Get-ChildItem -Path $smokeDir -Recurse -Force -Filter "._*" | Remove-Item -Force -ErrorAction SilentlyContinue

  $rid = "win-x64"
  $platform = "x64"
  if ($env:PROCESSOR_ARCHITECTURE -eq "ARM64") {
    $rid = "win-arm64"
    $platform = "ARM64"
  }
  $proj = Join-Path $smokeDir "PreviewHost.csproj"
  $smokeFlag = if ($FullRenderer) { "false" } else { "true" }
  Write-Host ("==> dotnet build PreviewHost (" + $rid + ", Smoke=" + $smokeFlag + ")")
  dotnet build $proj -c Release -p:Platform=$platform -p:RuntimeIdentifier=$rid -p:Smoke=$smokeFlag | Out-Host
  if ($LASTEXITCODE -ne 0) {
    if ($FullRenderer) {
      Write-Host "WARN: full AC renderer build failed — falling back to Smoke=true walker"
      return Ensure-PreviewHost -FullRenderer:$false
    }
    exit $LASTEXITCODE
  }
  $exe = Get-ChildItem -Path $smokeDir -Recurse -Filter "AcPreviewHost.exe" |
    Where-Object { $_.FullName -match "Release" } |
    Select-Object -First 1
  if ($null -eq $exe) {
    Write-Host "ERROR: AcPreviewHost.exe not found"
    exit 1
  }
  return [string]$exe.FullName
}

# --- smoke: cargo + WidgetProvider ---
if ($Mode -eq "smoke") {
  $cargoOk = $false
  if (-not $SkipCargo) {
    if (Test-MsvcLinker) {
      Write-Host "==> cargo test --lib adaptive_card"
      cargo test --lib adaptive_card -- --nocapture
      if ($LASTEXITCODE -eq 0) { $cargoOk = $true }
    } else {
      Write-Host "cargo: skipped (link.exe missing - run bootstrap.ps1)"
    }
  }

  if (-not $SkipDotnet) {
    $smokeDir = Join-Path $env:TEMP "tpw-windows-widget-smoke"
    if (Test-Path $smokeDir) { Remove-Item -Recurse -Force $smokeDir }
    $src = Join-Path $Repo "templates\windows-widget"
    Copy-Item -Recurse $src $smokeDir
    Get-ChildItem -Path $smokeDir -Recurse -Force -Filter "._*" | Remove-Item -Force -ErrorAction SilentlyContinue

    $clsid = [guid]::NewGuid().ToString()
    $replacements = @{
      "{{WIDGET_PROVIDER_CLSID}}" = $clsid
      "{{WIDGET_DISPLAY_NAME}}" = "Smoke"
      "{{PACKAGE_NAME}}" = "SmokeApp"
      "{{WIDGET_EXTENSION_ID}}" = "SmokeApp.Widgets"
      "{{WIDGET_DEFINITION_ID}}" = "SmokeApp.Widget"
    }
    Get-ChildItem -Path $smokeDir -Recurse -File | ForEach-Object {
      $text = Get-Content $_.FullName -Raw -ErrorAction SilentlyContinue
      if ($null -eq $text) { return }
      $changed = $false
      foreach ($k in $replacements.Keys) {
        if ($text.Contains($k)) {
          $text = $text.Replace($k, $replacements[$k])
          $changed = $true
        }
      }
      if ($changed) { Set-Content -Path $_.FullName -Value $text -NoNewline }
    }

    $provider = Join-Path $smokeDir "WidgetProvider\WidgetProvider.csproj"
    $rid = if ($env:PROCESSOR_ARCHITECTURE -eq "ARM64") { "win-arm64" } else { "win-x64" }
    $platform = if ($env:PROCESSOR_ARCHITECTURE -eq "ARM64") { "ARM64" } else { "x64" }
    Write-Host ("==> dotnet build WidgetProvider (" + $rid + ", Smoke=true)")
    dotnet build $provider -c Release -p:Platform=$platform -p:RuntimeIdentifier=$rid -p:Smoke=true
    if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
  }

  Write-Host "shot: OK (smoke)"
  exit 0
}

# --- visual: transpile cards + PreviewHost PNG (full AdaptiveCards.Rendering.Wpf) ---
$exe = Ensure-PreviewHost -FullRenderer:$true
$casesDir = Join-Path $Repo "tests\cases"
$goldenDir = Join-Path $Repo "tests\golden\windows"
$outDir = Join-Path $Repo "out\windows"
New-Item -ItemType Directory -Force -Path $goldenDir | Out-Null
New-Item -ItemType Directory -Force -Path $outDir | Out-Null

# Prefer prebuilt AC JSON from Mac sync under snapshots; else minimal card from case name.
$caseFiles = Get-ChildItem $casesDir -Filter "*.json"
if ($Case) {
  $caseFiles = $caseFiles | Where-Object { $_.BaseName -eq $Case }
}

foreach ($cf in $caseFiles) {
  $name = $cf.BaseName
  $caseJson = Get-Content $cf.FullName -Raw | ConvertFrom-Json
  $size = [string]$caseJson.size
  if (-not $size) { $size = "small" }

  $snap = Join-Path $Repo ("tests\snapshots\adaptive\" + $name + ".json")
  $cardPath = Join-Path $outDir ($name + ".card.json")
  if (Test-Path $snap) {
    Copy-Item $snap $cardPath -Force
  } else {
    # Minimal placeholder card so PreviewHost still produces a bitmap.
    $placeholder = @{
      type = "AdaptiveCard"
      version = "1.5"
      body = @(@{ type = "TextBlock"; text = $name; wrap = $true })
    } | ConvertTo-Json -Depth 5
    Set-Content -Path $cardPath -Value $placeholder -Encoding UTF8
  }

  $w = 158; $h = 158
  if ($size -eq "medium") { $w = 338; $h = 158 }
  if ($size -eq "large") { $w = 338; $h = 354 }

  $pngOut = Join-Path $outDir ($name + ".png")
  & $exe --in $cardPath --out $pngOut --width $w --height $h
  if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

  $golden = Join-Path $goldenDir ($name + ".png")
  if ($Record) {
    Copy-Item $pngOut $golden -Force
    Write-Host ("recorded " + $golden)
  } elseif (Test-Path $golden) {
    Write-Host ("captured " + $pngOut + " (compare golden on Mac)")
  } else {
    Write-Host ("captured " + $pngOut + " (no golden yet)")
  }
}

Write-Host "shot: OK (visual)"