$typesContent = @' export type PlatformType = "ANDROID" | "IOS"; export interface ComponentNode { id: string; name: string; type: string; icon?: string; order?: number; props: ComponentProps; children?: ComponentNode[]; pageId?: { id: string; name: string; }; } export interface ComponentProps { identifier: string; developer_notes?: string; api?: string; state?: string; api_action?: string; className?: string; dataVariable?: string; } export interface GlobalState { leftPanel: ComponentNode[]; middlePanel: ComponentNode[]; rightPanel: ComponentNode | null; selectedComponent: number; rightComponentId: string; selectedPageComponent: string; copiedComponent: ComponentNode | null; copiedPage: ComponentNode[]; selectedPageId: SelectedPageId; disabledComponent: boolean; } export interface SelectedPageId { id: string; name: string; } '@ if (-not (Test-Path ".\src\types\global.ts")) { New-Item -Path ".\src\types" -ItemType Directory -Force Set-Content -Path ".\src\types\global.ts" -Value $typesContent -NoNewline } $patterns = @( # Pattern 1: Add interface for components without props @{ 'Match' = '(?' 'Replace' = "interface `$1Props {}`n`nconst `$1: React.FC<`$1Props> = () =>" }, # Pattern 2: Add interface for components with destructured props @{ 'Match' = '(?' 'Replace' = { param($matches) $componentName = $matches[1] $propsText = $matches[2] $props = $propsText -split ',\s*' | Where-Object { $_ -match '\S' } | ForEach-Object { $prop = $_ -replace '=.*$', '' -replace '//.*$', '' -replace '\s+$', '' -replace '^\s+', '' if ($prop -match 'children') { " $prop: ReactNode;" } elseif ($prop -match 'type') { " $prop: PlatformType;" } elseif ($prop -match 'dispatch') { " $prop: React.Dispatch;" } elseif ($prop -match 'state') { " $prop: GlobalState;" } elseif ($prop -match 'ref') { " $prop?: React.RefObject;" } elseif ($prop -match 'style') { " $prop?: React.CSSProperties;" } elseif ($prop -match 'className') { " $prop?: string;" } elseif ($prop -match 'onClick|onSubmit|onChange|onBlur|onFocus') { " $prop?: (event: any) => void;" } elseif ($prop -match 'component') { " $prop?: ComponentNode;" } elseif ($prop -match 'components|leftPanel|middlePanel') { " $prop?: ComponentNode[];" } elseif ($prop -match 'componentId') { " $prop?: string;" } elseif ($prop -match '\[\]$') { " $prop?: ${prop};" } else { " $prop?: any;" } } $propsInterface = $props -join "`n" @" import { PlatformType, ComponentNode, GlobalState } from '@/types/global'; interface ${componentName}Props { $propsInterface } const $componentName: React.FC<${componentName}Props> = ({ $propsText }) => "@ } }, # Pattern 3: Add React.FC type to memo wrapped components @{ 'Match' = 'export\s+default\s+memo\((\w+)\)' 'Replace' = 'export default memo($1) as React.FC<$1Props>' }, # Pattern 4: Add return type to useEffect @{ 'Match' = 'useEffect\(\(\)\s*=>' 'Replace' = 'useEffect((): void =>' }, # Pattern 5: Add type for state variables @{ 'Match' = 'useState\(([^)]+)\)' 'Replace' = { param($matches) $initialValue = $matches[1].Trim() if ($initialValue -match '^\[\s*\]\s*$') { 'useState([])' } elseif ($initialValue -match '^\{\s*\}\s*$') { 'useState>({})' } elseif ($initialValue -match '^".*"$') { 'useState(' + $initialValue + ')' } elseif ($initialValue -match '^\d+(\.\d+)?$') { 'useState(' + $initialValue + ')' } elseif ($initialValue -match '^(true|false)$') { 'useState(' + $initialValue + ')' } elseif ($initialValue -match '^null$') { 'useState(null)' } elseif ($initialValue -match '^undefined$') { 'useState(undefined)' } else { 'useState(' + $initialValue + ')' } } } ) $srcPath = ".\src" $files = Get-ChildItem -Path $srcPath -Recurse -Include "*.tsx" foreach ($file in $files) { $content = Get-Content $file.FullName -Raw $modified = $false # Add necessary React imports if not present $reactImports = @() if (-not ($content -match '\bFC\b')) { $reactImports += "FC" } if (-not ($content -match '\bReactNode\b')) { $reactImports += "ReactNode" } if (-not ($content -match '\bCSSProperties\b') -and $content -match 'style\s*[?:]') { $reactImports += "CSSProperties" } if ($reactImports.Count -gt 0) { if ($content -match 'import\s+React,\s*{([^}]*?)}\s+from\s+[''"]react[''"]') { $existingImports = $matches[1] $newImports = ($reactImports | Where-Object { $existingImports -notmatch "\b$_\b" }) -join ", " if ($newImports) { $content = $content -replace 'import\s+React,\s*{([^}]*?)}\s+from\s+[''"]react[''"]', "import React, { `$1, $newImports } from 'react'" $modified = $true } } elseif ($content -match 'import\s+React\s+from\s+[''"]react[''"]') { $content = $content -replace 'import\s+React\s+from\s+[''"]react[''"]', "import React, { $($reactImports -join ', ') } from 'react'" $modified = $true } } foreach ($pattern in $patterns) { if ($content -match $pattern.Match) { if ($pattern.Replace -is [scriptblock]) { $content = [regex]::Replace($content, $pattern.Match, $pattern.Replace) } else { $content = $content -replace $pattern.Match, $pattern.Replace } $modified = $true } } if ($modified) { Write-Host "Adding types to: $($file.FullName)" $content | Set-Content $file.FullName -NoNewline } } Write-Host "Done adding types to components and pages."