@@ -80,28 +80,45 @@ Describe 'Architecture guardrails' {
8080 (Compare-Object - ReferenceObject $expected - DifferenceObject $actual ) | Should - BeNullOrEmpty - Because (($actual -join ' , ' ), (& $script :formatMatches - MatchList $matches ) -join [Environment ]::NewLine)
8181 }
8282
83- It ' public orchestration entrypoints keep delegating to their context and workflow helpers ' {
83+ It ' public command files use only their approved Nova helper surface ' {
8484 $testCases = @ (
85- [pscustomobject ]@ {Path = ' src/public/DeployNovaPackage.ps1' ; ContextPattern = ' \bGet-NovaPackageUploadWorkflowContext\b' ; ActionPattern = ' \bInvoke-NovaPackageUploadWorkflow\b' }
86- [pscustomobject ]@ {Path = ' src/public/InitializeNovaModule.ps1' ; ContextPattern = ' \bGet-NovaModuleInitializationWorkflowContext\b' ; ActionPattern = ' \bInvoke-NovaModuleInitializationWorkflow\b' }
87- [pscustomobject ]@ {Path = ' src/public/InstallNovaCli.ps1' ; ContextPattern = ' \bGet-NovaCliInstallWorkflowContext\b' ; ActionPattern = ' \bInvoke-NovaCliInstallWorkflow\b' }
88- [pscustomobject ]@ {Path = ' src/public/InvokeNovaBuild.ps1' ; ContextPattern = ' \bGet-NovaBuildWorkflowContext\b' ; ActionPattern = ' \bInvoke-NovaBuildWorkflow\b' }
89- [pscustomobject ]@ {Path = ' src/public/InvokeNovaCli.ps1' ; ContextPattern = ' \bGet-NovaCliInvocationContext\b' ; ActionPattern = ' \bInvoke-NovaCliCommandRoute\b' }
90- [pscustomobject ]@ {Path = ' src/public/InvokeNovaRelease.ps1' ; ContextPattern = ' \bGet-NovaPublishWorkflowContext\b' ; ActionPattern = ' \bInvoke-NovaReleaseWorkflow\b' }
91- [pscustomobject ]@ {Path = ' src/public/NewNovaModulePackage.ps1' ; ContextPattern = ' \bGet-NovaPackageWorkflowContext\b' ; ActionPattern = ' \bInvoke-NovaPackageWorkflow\b' }
92- [pscustomobject ]@ {Path = ' src/public/PublishNovaModule.ps1' ; ContextPattern = ' \bGet-NovaPublishWorkflowContext\b' ; ActionPattern = ' \bInvoke-NovaPublishWorkflow\b' }
93- [pscustomobject ]@ {Path = ' src/public/SetNovaUpdateNotificationPreference.ps1' ; ContextPattern = ' \bGet-NovaUpdateNotificationPreferenceChangeContext\b' ; ActionPattern = ' \bInvoke-NovaUpdateNotificationPreferenceChange\b' }
94- [pscustomobject ]@ {Path = ' src/public/TestNovaBuild.ps1' ; ContextPattern = ' \bGet-NovaTestWorkflowContext\b' ; ActionPattern = ' \bInvoke-NovaTestWorkflow\b' }
95- [pscustomobject ]@ {Path = ' src/public/UpdateNovaModuleTools.ps1' ; ContextPattern = ' \bGet-NovaModuleSelfUpdateWorkflowContext\b' ; ActionPattern = ' \bInvoke-NovaModuleSelfUpdateWorkflow\b' }
96- [pscustomobject ]@ {Path = ' src/public/UpdateNovaModuleVersion.ps1' ; ContextPattern = ' \bGet-NovaVersionUpdateWorkflowContext\b' ; ActionPattern = ' \bInvoke-NovaVersionUpdateWorkflow\b' }
85+ [pscustomobject ]@ {Path = ' src/public/DeployNovaPackage.ps1' ; ExpectedHelpers = @ (' Get-NovaPackageUploadWorkflowContext' , ' Get-NovaProjectInfo' , ' Invoke-NovaPackageUploadWorkflow' , ' New-NovaPackageUploadDynamicParameterDictionary' , ' New-NovaPackageUploadOption' )}
86+ [pscustomobject ]@ {Path = ' src/public/GetNovaProjectInfo.ps1' ; ExpectedHelpers = @ (' Get-NovaProjectInfoContext' , ' Get-NovaProjectInfoResult' )}
87+ [pscustomobject ]@ {Path = ' src/public/GetNovaUpdateNotificationPreference.ps1' ; ExpectedHelpers = @ (' Get-NovaUpdateNotificationPreferenceStatus' )}
88+ [pscustomobject ]@ {Path = ' src/public/InitializeNovaModule.ps1' ; ExpectedHelpers = @ (' Get-NovaModuleInitializationWorkflowContext' , ' Invoke-NovaModuleInitializationWorkflow' )}
89+ [pscustomobject ]@ {Path = ' src/public/InstallNovaCli.ps1' ; ExpectedHelpers = @ (' Get-NovaCliInstallWorkflowContext' , ' Invoke-NovaCliInstallWorkflow' , ' Write-NovaModuleReleaseNotesLink' )}
90+ [pscustomobject ]@ {Path = ' src/public/InvokeNovaBuild.ps1' ; ExpectedHelpers = @ (' Get-NovaBuildWorkflowContext' , ' Invoke-NovaBuildWorkflow' )}
91+ [pscustomobject ]@ {Path = ' src/public/InvokeNovaCli.ps1' ; ExpectedHelpers = @ (' Get-NovaCliInvocationContext' , ' Invoke-NovaCliCommandRoute' )}
92+ [pscustomobject ]@ {Path = ' src/public/InvokeNovaRelease.ps1' ; ExpectedHelpers = @ (' Get-NovaProjectInfo' , ' Get-NovaPublishWorkflowContext' , ' Get-NovaShouldProcessForwardingParameter' , ' Invoke-NovaReleaseWorkflow' , ' Write-NovaPublishWorkflowContext' )}
93+ [pscustomobject ]@ {Path = ' src/public/NewNovaModulePackage.ps1' ; ExpectedHelpers = @ (' Get-NovaPackageWorkflowContext' , ' Get-NovaShouldProcessForwardingParameter' , ' Invoke-NovaPackageWorkflow' )}
94+ [pscustomobject ]@ {Path = ' src/public/PublishNovaModule.ps1' ; ExpectedHelpers = @ (' Get-NovaDynamicDeliveryParameterDictionary' , ' Get-NovaProjectInfo' , ' Get-NovaPublishWorkflowContext' , ' Get-NovaShouldProcessForwardingParameter' , ' Invoke-NovaPublishWorkflow' , ' Write-NovaPublishWorkflowContext' )}
95+ [pscustomobject ]@ {Path = ' src/public/SetNovaUpdateNotificationPreference.ps1' ; ExpectedHelpers = @ (' Get-NovaUpdateNotificationPreferenceChangeContext' , ' Invoke-NovaUpdateNotificationPreferenceChange' )}
96+ [pscustomobject ]@ {Path = ' src/public/TestNovaBuild.ps1' ; ExpectedHelpers = @ (' Get-NovaTestWorkflowContext' , ' Invoke-NovaTestWorkflow' , ' New-NovaTestDynamicParameterDictionary' )}
97+ [pscustomobject ]@ {Path = ' src/public/UpdateNovaModuleTools.ps1' ; ExpectedHelpers = @ (' Complete-NovaModuleSelfUpdateResult' , ' Confirm-NovaPrereleaseModuleUpdate' , ' Get-NovaModuleSelfUpdateWorkflowContext' , ' Invoke-NovaModuleSelfUpdateWorkflow' , ' Write-NovaModuleReleaseNotesLink' )}
98+ [pscustomobject ]@ {Path = ' src/public/UpdateNovaModuleVersion.ps1' ; ExpectedHelpers = @ (' Get-NovaVersionUpdateCiActivatedCommand' , ' Get-NovaVersionUpdateWorkflowContext' , ' Invoke-NovaVersionUpdateWorkflow' )}
9799 )
100+ $expectedPaths = @ ($testCases | ForEach-Object Path | Sort-Object )
101+ $actualPaths = @ (
102+ Get-ChildItem - LiteralPath (Join-Path $script :srcRoot ' public' ) - Filter ' *.ps1' - File |
103+ ForEach-Object {([System.IO.Path ]::GetRelativePath($script :repoRoot , $_.FullName )).Replace(' \' , ' /' )} |
104+ Sort-Object
105+ )
106+
107+ (Compare-Object - ReferenceObject $expectedPaths - DifferenceObject $actualPaths ) | Should - BeNullOrEmpty - Because " Public command allowlist should stay in sync with src/public. Expected: $ ( $expectedPaths -join ' , ' ) | Actual: $ ( $actualPaths -join ' , ' ) "
98108
99109 foreach ($testCase in $testCases ) {
100110 $filePath = Join-Path $script :repoRoot $testCase.Path
101- $content = Get-Content - LiteralPath $filePath - Raw
102-
103- $content | Should -Match $testCase.ContextPattern - Because " $ ( $testCase.Path ) should build or resolve its workflow/context state before orchestration"
104- $content | Should -Match $testCase.ActionPattern - Because " $ ( $testCase.Path ) should delegate execution to its workflow or routing helper"
111+ $null = $tokens = $parseErrors = $null
112+ $ast = [System.Management.Automation.Language.Parser ]::ParseFile($filePath , [ref ]$tokens , [ref ]$parseErrors )
113+ $actualHelpers = @ (
114+ $ast.FindAll ({param ($node ) $node -is [System.Management.Automation.Language.CommandAst ]}, $true ) |
115+ ForEach-Object {$_.GetCommandName ()} |
116+ Where-Object {$_ -like ' *Nova*' } |
117+ Sort-Object - Unique
118+ )
119+ $expectedHelpers = @ ($testCase.ExpectedHelpers | Sort-Object - Unique)
120+
121+ (Compare-Object - ReferenceObject $expectedHelpers - DifferenceObject $actualHelpers ) | Should - BeNullOrEmpty - Because " $ ( $testCase.Path ) should only use its approved Nova helper surface. Expected: $ ( $expectedHelpers -join ' , ' ) | Actual: $ ( $actualHelpers -join ' , ' ) "
105122 }
106123 }
107124
0 commit comments