proj.ps1
|
# Copyright 2026 gor-dey # Licensed under the Apache License, Version 2.0 (the "License") # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software distributed under the License is "AS IS" BASIS. # --- Fix Encoding for PowerShell 5.1 --- if ($PSVersionTable.PSVersion.Major -le 5) { [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 $OutputEncoding = [System.Text.Encoding]::UTF8 } # --- Load Constants --- $ScriptRoot = $PSScriptRoot . (Join-Path $ScriptRoot "constants.ps1") # --- DATA STORAGE SETUP --- if (-not (Test-Path $NoxConfigDir)) { New-Item -ItemType Directory -Force -Path $NoxConfigDir | Out-Null } if (-not (Test-Path $NoxProjFile)) { "{}" | Set-Content $NoxProjFile -Encoding UTF8 } if (-not (Test-Path $NoxLangFile)) { "en" | Set-Content $NoxLangFile -Encoding UTF8 } function proj { [CmdletBinding()] param( [Parameter(Position = 0)] [ValidateSet("list", "add", "remove", "rename", "run", "go")] [string]$Action, [Parameter(Position = 1)] [ArgumentCompleter({ param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $action = $fakeBoundParameters['Action'] if ($action -match 'run|remove|go|rename') { $projFile = Join-Path (Join-Path $HOME ".config\FrontNox") "proj.json" if (Test-Path $projFile) { $map = Get-Content $projFile -Raw -Encoding UTF8 | ConvertFrom-Json return $map.psobject.Properties.Name | Where-Object { $_ -like "$wordToComplete*" } } } return $null })] [string]$Name, [Parameter(Position = 2)] [string]$NewName, [switch]$Version ) # --- Load messages once per invocation --- $Lang = if (Test-Path $NoxLangFile) { (Get-Content $NoxLangFile -Raw -Encoding UTF8).Trim() } else { "en" } $I18nPath = Join-Path $NoxI18nDir "$Lang.json" if (-not (Test-Path $I18nPath)) { $I18nPath = Join-Path $NoxI18nDir "en.json" } $Messages = Get-Content $I18nPath -Raw -Encoding UTF8 | ConvertFrom-Json function Get-Msg($Key, $Arg1, $Arg2) { $m = $Messages.proj.$Key if ($Arg2) { return $m -f $Arg1, $Arg2 } if ($Arg1) { return $m -f $Arg1 } return $m } function Test-ProjName($n) { if ($n -notmatch '^[a-zA-Z0-9_\.\-]{1,50}$') { Write-Host $(Get-Msg ErrBadName) -ForegroundColor Red return $false } return $true } if ($Version) { Write-Host "FrontNox v$NoxVersion" return } if (-not $Action) { Write-Host (Get-Msg Usage) -ForegroundColor Gray return } # Reload project map from disk $ProjMap = Get-Content $NoxProjFile -Raw -Encoding UTF8 | ConvertFrom-Json switch ($Action) { "list" { Write-Host "`n$(Get-Msg Header)" -ForegroundColor Cyan if (@($ProjMap.psobject.Properties).Count -eq 0) { Write-Host $(Get-Msg Empty) -ForegroundColor DarkGray } else { $esc = [char]27 foreach ($prop in $ProjMap.psobject.Properties) { $path = $prop.Value try { $uri = ([Uri]$path).AbsoluteUri } catch { $uri = $path } $clickablePath = "$esc]8;;$uri$esc\$path$esc]8;;$esc\" Write-Host " $($prop.Name)" -NoNewline -ForegroundColor White Write-Host " -> " -NoNewline -ForegroundColor DarkGray Write-Host $clickablePath -ForegroundColor Gray } } Write-Host "" } "add" { if (-not $Name) { Write-Host $(Get-Msg ErrNameReq) -ForegroundColor Red return } if (-not (Test-ProjName $Name)) { return } $Path = (Get-Location).Path if ($null -eq $ProjMap.psobject.Properties[$Name]) { $ProjMap | Add-Member -MemberType NoteProperty -Name $Name -Value $Path } else { $ProjMap.$Name = $Path } $ProjMap | ConvertTo-Json | Set-Content $NoxProjFile -Encoding UTF8 Write-Host $(Get-Msg Saved $Name) -ForegroundColor Green } "remove" { if (-not $Name) { Write-Host $(Get-Msg ErrNameReq) -ForegroundColor Red return } if ($null -ne $ProjMap.psobject.Properties[$Name]) { $ProjMap.psobject.Properties.Remove($Name) $ProjMap | ConvertTo-Json | Set-Content $NoxProjFile -Encoding UTF8 Write-Host $(Get-Msg Removed $Name) -ForegroundColor Yellow } else { Write-Host $(Get-Msg NotFound $Name) -ForegroundColor DarkGray } } "rename" { if (-not $Name -or -not $NewName) { Write-Host $(Get-Msg ErrRenameArgs) -ForegroundColor Red return } if (-not (Test-ProjName $Name)) { return } if (-not (Test-ProjName $NewName)) { return } if ($null -eq $ProjMap.psobject.Properties[$Name]) { Write-Host $(Get-Msg NotFound $Name) -ForegroundColor Red return } if ($null -ne $ProjMap.psobject.Properties[$NewName]) { Write-Host $(Get-Msg ErrRenameExists $NewName) -ForegroundColor Red return } $Path = $ProjMap.$Name $ProjMap.psobject.Properties.Remove($Name) $ProjMap | Add-Member -MemberType NoteProperty -Name $NewName -Value $Path $ProjMap | ConvertTo-Json | Set-Content $NoxProjFile -Encoding UTF8 Write-Host $(Get-Msg Renamed $Name $NewName) -ForegroundColor Green } "run" { if (-not $Name) { Write-Host $(Get-Msg ErrNameReq) -ForegroundColor Red return } if ($Name -eq '.') { $p = (Get-Location).Path } else { $p = $ProjMap.$Name } if ($p -and (Test-Path $p)) { Set-Location $p $launchMsg = if ($Name -eq '.') { Get-Msg LaunchingCwd $p } else { Get-Msg Launching $p } Write-Host "`n$launchMsg" -ForegroundColor Cyan if (Test-Path "package.json") { # Detect package manager by lock file $pm = "npm" if (Test-Path "bun.lockb") { $pm = "bun" } elseif (Test-Path "pnpm-lock.yaml") { $pm = "pnpm" } elseif (Test-Path "yarn.lock") { $pm = "yarn" } if ($pm -ne "npm") { Write-Host $(Get-Msg DetectedPM $pm) -ForegroundColor DarkGray } if (-not (Test-Path "node_modules")) { Write-Host $(Get-Msg MissingNodes $pm) -ForegroundColor Yellow & $pm install if ($LASTEXITCODE -ne 0) { Write-Host $(Get-Msg InstallFail $pm) -ForegroundColor Red return } } try { $pkg = Get-Content "package.json" -Raw -Encoding UTF8 | ConvertFrom-Json $scripts = $pkg.scripts.psobject.Properties.Name $cmd = if ($scripts -contains "dev") { "dev" } elseif ($scripts -contains "start") { "start" } else { $null } if ($cmd) { Write-Host $(Get-Msg Executing $pm $cmd) -ForegroundColor Gray & $pm run $cmd } else { Write-Host $(Get-Msg NoScripts) -ForegroundColor Yellow Write-Host $(Get-Msg Available ($scripts -join ', ')) -ForegroundColor DarkGray } } catch { Write-Host $(Get-Msg InvalidPkg) -ForegroundColor Red } } else { Write-Host $(Get-Msg NoPkg) -ForegroundColor DarkGray } } else { Write-Host $(Get-Msg NotFound $Name) -ForegroundColor Red } } "go" { if (-not $Name) { Write-Host $(Get-Msg ErrNameReq) -ForegroundColor Red return } $p = $ProjMap.$Name if ($p -and (Test-Path $p)) { Set-Location -Path $p Write-Host " $p" -ForegroundColor Gray } else { Write-Host $(Get-Msg NotFound $Name) -ForegroundColor Red } } } } |