Expose import defaults and selection evidence
This commit is contained in:
@@ -52,6 +52,40 @@ type importDefaults struct {
|
||||
pattern []string
|
||||
}
|
||||
|
||||
// ImportDefaults transports root-owned load defaults across the facade
|
||||
// boundary. Load options snapshot this value before source acquisition.
|
||||
type ImportDefaults struct {
|
||||
// Required controls absence handling when non-nil.
|
||||
Required *bool
|
||||
// Follow controls symlink following when non-nil.
|
||||
Follow *bool
|
||||
// Hidden controls hidden-entry discovery when non-nil.
|
||||
Hidden *bool
|
||||
// Recursive controls descendant directory traversal when non-nil.
|
||||
Recursive *bool
|
||||
// Pattern filters directory-search filenames; nil and empty differ.
|
||||
Pattern []string
|
||||
}
|
||||
|
||||
// OptionsWithImportDefaults copies root-owned defaults into ordinary options.
|
||||
func OptionsWithImportDefaults[T any](options Options[T], value ImportDefaults) Options[T] {
|
||||
options.importDefaults = privateImportDefaults(value)
|
||||
return options
|
||||
}
|
||||
|
||||
// LayeredOptionsWithImportDefaults copies root-owned defaults into grouped options.
|
||||
func LayeredOptionsWithImportDefaults[T any](options LayeredOptions[T], value ImportDefaults) LayeredOptions[T] {
|
||||
options.importDefaults = privateImportDefaults(value)
|
||||
return options
|
||||
}
|
||||
|
||||
func privateImportDefaults(value ImportDefaults) importDefaults {
|
||||
return snapshotImportDefaults(importDefaults{
|
||||
required: value.Required, follow: value.Follow, hidden: value.Hidden,
|
||||
recursive: value.Recursive, pattern: value.Pattern,
|
||||
})
|
||||
}
|
||||
|
||||
type resolvedImportPolicy struct {
|
||||
required bool
|
||||
follow bool
|
||||
|
||||
@@ -24,17 +24,18 @@ type Definition[T any] struct {
|
||||
// Imports enables explicit import declarations; Overlay selects one fixed overlay;
|
||||
// Overrides contains only values explicitly supplied by an application CLI.
|
||||
type Options[T any] struct {
|
||||
Definition Definition[T]
|
||||
Imports bool
|
||||
Overlay string
|
||||
Filesystem *FilesystemContext
|
||||
Overrides []Override
|
||||
SourceVersionMode sourceVersionMode
|
||||
importDefaults importDefaults
|
||||
destination Path
|
||||
placementMode placementMode
|
||||
sequencePolicy sequencePolicy
|
||||
deferAssembly bool
|
||||
Definition Definition[T]
|
||||
Imports bool
|
||||
Overlay string
|
||||
Filesystem *FilesystemContext
|
||||
Overrides []Override
|
||||
SourceVersionMode sourceVersionMode
|
||||
importDefaults importDefaults
|
||||
destination Path
|
||||
placementMode placementMode
|
||||
sequencePolicy sequencePolicy
|
||||
deferAssembly bool
|
||||
importDefaultsValidated bool
|
||||
}
|
||||
|
||||
// FilesystemContext supplies filesystem roots for imports and overlays.
|
||||
|
||||
@@ -48,7 +48,8 @@ func loadGroupedWithSecretLookup[T any](request loadRequest[T], secrets SecretBi
|
||||
request.definition.sequenceRegistrations = nil
|
||||
mainOptions, mainDiagnostics := selectOptions(request.main.source, []Options[T]{{
|
||||
Definition: request.definition, Imports: request.main.imports, Filesystem: request.main.filesystem, destination: request.main.destination.clone(),
|
||||
SourceVersionMode: request.sourceVersionMode, placementMode: request.main.placementMode, importDefaults: request.importDefaults,
|
||||
SourceVersionMode: request.sourceVersionMode, placementMode: request.main.placementMode,
|
||||
importDefaults: request.importDefaults, importDefaultsValidated: true,
|
||||
}})
|
||||
request.main.destination = mainOptions.destination
|
||||
diagnostics = append(diagnostics, mainDiagnostics...)
|
||||
@@ -56,7 +57,10 @@ func loadGroupedWithSecretLookup[T any](request loadRequest[T], secrets SecretBi
|
||||
for groupIndex := range request.underlays {
|
||||
for inputIndex := range request.underlays[groupIndex].inputs {
|
||||
input := &request.underlays[groupIndex].inputs[inputIndex]
|
||||
inputOptions, inputDiagnostics := selectOptions(input.source, []Options[T]{{Imports: input.imports, Filesystem: input.filesystem, destination: input.destination.clone(), placementMode: input.placementMode, importDefaults: request.importDefaults}})
|
||||
inputOptions, inputDiagnostics := selectOptions(input.source, []Options[T]{{
|
||||
Imports: input.imports, Filesystem: input.filesystem, destination: input.destination.clone(), placementMode: input.placementMode,
|
||||
importDefaults: request.importDefaults, importDefaultsValidated: true,
|
||||
}})
|
||||
input.destination = inputOptions.destination
|
||||
diagnostics = append(diagnostics, inputDiagnostics...)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,10 @@ func selectOptions[T any](source Source, supplied []Options[T]) (Options[T], []D
|
||||
options = supplied[0]
|
||||
}
|
||||
options.importDefaults = snapshotImportDefaults(options.importDefaults)
|
||||
diagnostics := validateImportDefaults(options.importDefaults)
|
||||
var diagnostics []Diagnostic
|
||||
if !options.importDefaultsValidated {
|
||||
diagnostics = validateImportDefaults(options.importDefaults)
|
||||
}
|
||||
if options.placementMode != placementModeMapping && options.placementMode != placementModeSequenceItem {
|
||||
diagnostics = append(diagnostics, optionDiagnostic(CodeOptionsInvalid, "input placement mode is invalid"))
|
||||
}
|
||||
|
||||
@@ -207,6 +207,90 @@ type importSelectionEvidence struct {
|
||||
outcome importSelectionOutcome
|
||||
}
|
||||
|
||||
// ImportSelectionForFacade is a root-converted source-selection transport
|
||||
// record. Its paths and enum spellings are converted by the facade.
|
||||
type ImportSelectionForFacade struct {
|
||||
Path Path // source-local import declaration path
|
||||
Location Location // authored location and declaring source ID
|
||||
Selector string // path, dir, or glob
|
||||
Outcome string // none for a completed empty optional selection
|
||||
}
|
||||
|
||||
// SourceInfoImportSelectionsForFacade returns detached selection records for
|
||||
// explicit root-owned conversion.
|
||||
func SourceInfoImportSelectionsForFacade(source SourceInfo) []ImportSelectionForFacade {
|
||||
if source.importSelections == nil {
|
||||
return nil
|
||||
}
|
||||
result := make([]ImportSelectionForFacade, len(source.importSelections))
|
||||
for index, selection := range source.importSelections {
|
||||
result[index] = ImportSelectionForFacade{
|
||||
Path: selection.path.clone(), Location: selection.location,
|
||||
Selector: importSelectorString(selection.selector),
|
||||
Outcome: importSelectionOutcomeString(selection.outcome),
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// SourceInfoWithImportSelections copies converted root-owned records into
|
||||
// private engine source evidence.
|
||||
func SourceInfoWithImportSelections(source SourceInfo, selections []ImportSelectionForFacade) SourceInfo {
|
||||
if selections == nil {
|
||||
source.importSelections = nil
|
||||
return source
|
||||
}
|
||||
source.importSelections = make([]importSelectionEvidence, len(selections))
|
||||
for index, selection := range selections {
|
||||
source.importSelections[index] = importSelectionEvidence{
|
||||
path: selection.Path.clone(), location: selection.Location,
|
||||
selector: importSelectorFromString(selection.Selector),
|
||||
outcome: importSelectionOutcomeFromString(selection.Outcome),
|
||||
}
|
||||
}
|
||||
return source
|
||||
}
|
||||
|
||||
func importSelectorString(value importSelector) string {
|
||||
switch value {
|
||||
case importSelectorPath:
|
||||
return "path"
|
||||
case importSelectorDirectory:
|
||||
return "dir"
|
||||
case importSelectorGlob:
|
||||
return "glob"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func importSelectorFromString(value string) importSelector {
|
||||
switch value {
|
||||
case "path":
|
||||
return importSelectorPath
|
||||
case "dir":
|
||||
return importSelectorDirectory
|
||||
case "glob":
|
||||
return importSelectorGlob
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func importSelectionOutcomeString(value importSelectionOutcome) string {
|
||||
if value == importSelectionNone {
|
||||
return "none"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func importSelectionOutcomeFromString(value string) importSelectionOutcome {
|
||||
if value == "none" {
|
||||
return importSelectionNone
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// SourceInfoPlacementModeForFacade converts private placement evidence to its
|
||||
// root-owned numeric representation.
|
||||
func SourceInfoPlacementModeForFacade(source SourceInfo) uint8 {
|
||||
|
||||
Reference in New Issue
Block a user