An experimental TypeSpec syntax for Lexicon
at main 5.6 kB view raw
1#!/bin/bash 2set -e 3 4# Usage: ./scripts/publish-all.sh <version> [--dry] 5# Example: ./scripts/publish-all.sh 0.4.0 6# Example: ./scripts/publish-all.sh 0.4.0 --dry 7 8if [ -z "$1" ]; then 9 echo "Error: Version argument required" 10 echo "Usage: ./scripts/publish-all.sh <version> [--dry]" 11 echo "Example: ./scripts/publish-all.sh 0.4.0" 12 echo "Example: ./scripts/publish-all.sh 0.4.0 --dry" 13 exit 1 14fi 15 16VERSION="$1" 17DRY_RUN=false 18 19if [ "$2" = "--dry" ]; then 20 DRY_RUN=true 21fi 22 23# Validate version format (basic semver check) 24if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then 25 echo "Error: Invalid version format. Use semver format (e.g., 0.4.0 or 0.4.0-beta.1)" 26 exit 1 27fi 28 29echo "📦 Publishing all packages at version $VERSION" 30echo "" 31 32# Get the root directory 33ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" 34cd "$ROOT_DIR" 35 36# Find all package.json files in packages/* 37ALL_PACKAGES=($(find packages -maxdepth 2 -name "package.json" -not -path "*/node_modules/*" | sort)) 38 39# Filter out private packages and topologically sort by dependencies 40PACKAGES=($(node -e " 41 const fs = require('fs'); 42 const allPackages = process.argv.slice(1); 43 44 // Filter out private packages 45 const packages = allPackages.filter(path => { 46 const pkg = JSON.parse(fs.readFileSync(path, 'utf-8')); 47 return !pkg.private; 48 }); 49 50 // Build dependency graph 51 const graph = new Map(); 52 const pkgNames = new Map(); 53 54 packages.forEach(path => { 55 const pkg = JSON.parse(fs.readFileSync(path, 'utf-8')); 56 pkgNames.set(pkg.name, path); 57 58 const deps = new Set(); 59 [pkg.dependencies, pkg.devDependencies, pkg.peerDependencies].forEach(depObj => { 60 if (depObj) { 61 Object.keys(depObj).forEach(dep => { 62 if (dep.startsWith('@typelex/')) { 63 deps.add(dep); 64 } 65 }); 66 } 67 }); 68 69 graph.set(pkg.name, deps); 70 }); 71 72 // Topological sort - packages with more dependents first 73 const sorted = []; 74 const processed = new Set(); 75 76 function visit(pkgName) { 77 if (processed.has(pkgName)) return; 78 processed.add(pkgName); 79 80 // Visit all dependencies first 81 const deps = graph.get(pkgName) || new Set(); 82 deps.forEach(dep => { 83 if (graph.has(dep)) { 84 visit(dep); 85 } 86 }); 87 88 sorted.push(pkgName); 89 } 90 91 // Visit all packages 92 graph.forEach((_, pkgName) => visit(pkgName)); 93 94 // Output sorted package paths 95 sorted.forEach(name => { 96 if (pkgNames.has(name)) { 97 console.log(pkgNames.get(name)); 98 } 99 }); 100" "${ALL_PACKAGES[@]}")) 101 102if [ ${#PACKAGES[@]} -eq 0 ]; then 103 echo "Error: No publishable packages found in packages/" 104 exit 1 105fi 106 107echo "Found ${#PACKAGES[@]} publishable packages (topologically sorted):" 108for pkg in "${PACKAGES[@]}"; do 109 PKG_NAME=$(node -p "require('./$pkg').name") 110 echo " - $PKG_NAME" 111done 112echo "" 113 114# Update all package.json files with the new version 115echo "🔄 Updating versions in all packages..." 116for pkg in "${PACKAGES[@]}"; do 117 PKG_DIR=$(dirname "$pkg") 118 PKG_NAME=$(node -p "require('./$pkg').name") 119 120 echo " Updating $PKG_NAME..." 121 122 # Update version 123 node -e " 124 const fs = require('fs'); 125 const path = '$pkg'; 126 const pkg = require('./' + path); 127 pkg.version = '$VERSION'; 128 129 // Helper to preserve semver prefix (^, ~, etc.) and workspace: protocol 130 function updateVersion(currentVersion, newVersion) { 131 // Preserve workspace: protocol for monorepo 132 if (currentVersion.startsWith('workspace:')) { 133 return currentVersion; 134 } 135 // Preserve semver prefix 136 const match = currentVersion.match(/^([~^>=<]*)(.*)$/); 137 if (match) { 138 return match[1] + newVersion; 139 } 140 return newVersion; 141 } 142 143 // Helper to update dependencies 144 function updateDeps(deps) { 145 if (!deps) return; 146 for (const dep in deps) { 147 if (dep.startsWith('@typelex/')) { 148 deps[dep] = updateVersion(deps[dep], '$VERSION'); 149 } 150 } 151 } 152 153 updateDeps(pkg.dependencies); 154 updateDeps(pkg.devDependencies); 155 updateDeps(pkg.peerDependencies); 156 157 fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + '\n'); 158 " 159done 160 161echo "" 162echo "✅ All versions updated to $VERSION" 163echo "" 164 165if [ "$DRY_RUN" = true ]; then 166 echo "✅ Dry run complete! Version updates have been applied." 167 echo "" 168 echo "📋 Updated packages:" 169 for pkg in "${PACKAGES[@]}"; do 170 PKG_NAME=$(node -p "require('./$pkg').name") 171 echo " - $PKG_NAME@$VERSION" 172 done 173 echo "" 174 echo "💡 Review the changes, then run without --dry to publish." 175 exit 0 176fi 177 178# Ask for confirmation 179read -p "🚀 Ready to publish all packages to npm. Continue? (y/N) " -n 1 -r 180echo 181if [[ ! $REPLY =~ ^[Yy]$ ]]; then 182 echo "❌ Publish cancelled" 183 exit 1 184fi 185 186echo "" 187echo "📤 Publishing packages..." 188echo "" 189 190# Publish each package 191PUBLISHED=() 192FAILED=() 193 194for pkg in "${PACKAGES[@]}"; do 195 PKG_DIR=$(dirname "$pkg") 196 PKG_NAME=$(node -p "require('./$pkg').name") 197 198 echo "Publishing $PKG_NAME..." 199 200 if (cd "$PKG_DIR" && npm publish --access public); then 201 echo "$PKG_NAME published successfully" 202 PUBLISHED+=("$PKG_NAME") 203 else 204 echo "$PKG_NAME failed to publish" 205 FAILED+=("$PKG_NAME") 206 fi 207 208 echo "" 209done 210 211# Summary 212echo "📊 Summary:" 213echo "" 214echo "Published (${#PUBLISHED[@]}):" 215for pkg in "${PUBLISHED[@]}"; do 216 echo "$pkg" 217done 218 219if [ ${#FAILED[@]} -gt 0 ]; then 220 echo "" 221 echo "Failed (${#FAILED[@]}):" 222 for pkg in "${FAILED[@]}"; do 223 echo "$pkg" 224 done 225 exit 1 226fi 227 228echo "" 229echo "🎉 All packages published successfully!"