118 lines
4.8 KiB
PowerShell
118 lines
4.8 KiB
PowerShell
param(
|
|
[string]$Root = (Get-Location).Path,
|
|
[switch]$Json
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
if (-not (Test-Path -LiteralPath $Root)) {
|
|
throw "Root path does not exist: $Root"
|
|
}
|
|
|
|
$rootPath = (Resolve-Path -LiteralPath $Root).Path
|
|
$excludedDirs = @(".git", "node_modules", "vendor", "dist", "build", "target", ".next", ".idea", ".vscode")
|
|
|
|
function Get-RelativePath {
|
|
param([string]$Path)
|
|
|
|
$fullPath = (Resolve-Path -LiteralPath $Path).Path
|
|
if ($fullPath.StartsWith($rootPath, [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
return ($fullPath.Substring($rootPath.Length).TrimStart([char[]]"\/") -replace "\\", "/")
|
|
}
|
|
|
|
return ($fullPath -replace "\\", "/")
|
|
}
|
|
|
|
function Test-IsExcluded {
|
|
param([string]$Path)
|
|
|
|
$relativePath = Get-RelativePath -Path $Path
|
|
$parts = $relativePath -split "/"
|
|
foreach ($part in $parts) {
|
|
if ($excludedDirs -contains $part) {
|
|
return $true
|
|
}
|
|
}
|
|
|
|
return $false
|
|
}
|
|
|
|
$files = @(Get-ChildItem -Path $rootPath -Recurse -File -Force | Where-Object { -not (Test-IsExcluded -Path $_.FullName) })
|
|
$directories = @(Get-ChildItem -Path $rootPath -Recurse -Directory -Force | Where-Object { -not (Test-IsExcluded -Path $_.FullName) })
|
|
|
|
$signals = New-Object System.Collections.Generic.List[object]
|
|
|
|
function Add-Signal {
|
|
param(
|
|
[string]$Name,
|
|
[string]$Confidence,
|
|
[string]$Reason,
|
|
[string[]]$Evidence
|
|
)
|
|
|
|
$existing = @($signals | Where-Object { $_.name -eq $Name })
|
|
if ($existing.Count -gt 0) {
|
|
return
|
|
}
|
|
|
|
[void]$signals.Add([pscustomobject]@{
|
|
name = $Name
|
|
confidence = $Confidence
|
|
reason = $Reason
|
|
evidence = @($Evidence)
|
|
})
|
|
}
|
|
|
|
$sqlFiles = @($files | Where-Object { $_.Extension -match "^\.(sql|dbml)$" })
|
|
$ormFiles = @($files | Where-Object { $_.Name -match "(?i)(schema\.prisma|sequelize|typeorm|entity|model|migration)" })
|
|
$dbDirs = @($directories | Where-Object { $_.Name -match "(?i)^(db|database|migrations|migration|models|entities|dao|mapper|repository|doc-sql)$" })
|
|
$databaseConfig = @($files | Where-Object { $_.Name -match "(?i)(database|datasource|jdbc|gorm|mybatis|hibernate|prisma|knex|typeorm)" })
|
|
|
|
if ($sqlFiles.Count -gt 0 -or $ormFiles.Count -gt 0 -or $dbDirs.Count -gt 0 -or $databaseConfig.Count -gt 0) {
|
|
$evidence = @($sqlFiles + $ormFiles + $databaseConfig | Select-Object -First 8 | ForEach-Object { Get-RelativePath -Path $_.FullName })
|
|
$evidence += @($dbDirs | Select-Object -First 5 | ForEach-Object { Get-RelativePath -Path $_.FullName })
|
|
Add-Signal -Name "project-has-database" -Confidence "high" -Reason "Database files, ORM files, database directories, or database configs were found." -Evidence $evidence
|
|
}
|
|
|
|
$tableDesignDocs = @($files | Where-Object { (Get-RelativePath -Path $_.FullName) -match "(?i)(doc-sql|table|schema|database|data-model)" })
|
|
if ($tableDesignDocs.Count -gt 0) {
|
|
Add-Signal -Name "designing-tables" -Confidence "medium" -Reason "Database or table-design documentation paths were found." -Evidence @($tableDesignDocs | Select-Object -First 8 | ForEach-Object { Get-RelativePath -Path $_.FullName })
|
|
}
|
|
|
|
$syncFiles = @($files | Where-Object { $_.Name -match "(?i)(sync|import|export|reconcile|recovery|recover|external|serial|code|number)" })
|
|
if ($syncFiles.Count -gt 0) {
|
|
Add-Signal -Name "data-may-sync-or-recover" -Confidence "medium" -Reason "Sync, import/export, recovery, external-code, or number-related names were found." -Evidence @($syncFiles | Select-Object -First 8 | ForEach-Object { Get-RelativePath -Path $_.FullName })
|
|
}
|
|
|
|
$apiFiles = @($files | Where-Object { $_.Name -match "(?i)(openapi|swagger|controller|router|route|api)" })
|
|
if ($apiFiles.Count -gt 0) {
|
|
Add-Signal -Name "has-api-contract" -Confidence "medium" -Reason "API contract, router, route, or controller files were found." -Evidence @($apiFiles | Select-Object -First 8 | ForEach-Object { Get-RelativePath -Path $_.FullName })
|
|
}
|
|
|
|
$frontendFiles = @($files | Where-Object { $_.Extension -match "^\.(tsx|jsx|vue|svelte)$" -or $_.Name -match "(?i)(component|page|view|route|menu|form)" })
|
|
if ($frontendFiles.Count -gt 0) {
|
|
Add-Signal -Name "has-frontend-ui" -Confidence "medium" -Reason "Frontend page, component, route, menu, or form files were found." -Evidence @($frontendFiles | Select-Object -First 8 | ForEach-Object { Get-RelativePath -Path $_.FullName })
|
|
}
|
|
|
|
$result = [pscustomobject]@{
|
|
root = $rootPath
|
|
signals = @($signals.ToArray())
|
|
}
|
|
|
|
if ($Json) {
|
|
ConvertTo-Json -InputObject $result -Depth 8
|
|
return
|
|
}
|
|
|
|
if ($signals.Count -eq 0) {
|
|
Write-Host "No project signals detected."
|
|
return
|
|
}
|
|
|
|
foreach ($signal in $signals) {
|
|
Write-Host "$($signal.name) [$($signal.confidence)] - $($signal.reason)"
|
|
foreach ($item in @($signal.evidence)) {
|
|
Write-Host " - $item"
|
|
}
|
|
}
|