2026-09-06 21:55:35 +00:00
package configkit
import (
"math"
"reflect"
"slices"
"strconv"
"strings"
"unicode"
"unicode/utf8"
"gitea.maximumdirect.net/eric/ConfigKit/internal/document"
)
const maxOverrides = 1024
type preparedOverride struct {
path Path
value * document . Node
source SourceInfo
bytes int64
nodes int
}
type overrideValueBuilder struct {
sourceID string
active map [ valueVisit ] bool
bytes int64
nodes int
}
func applyOverrides ( base * composedDocument , sources [ ] SourceInfo , overrides [ ] Override , rule * VersionRule , limits importLimits ) ( * composedDocument , [ ] SourceInfo , [ ] Diagnostic ) {
if len ( overrides ) == 0 {
return base , cloneSourceInfos ( sources ) , nil
}
if len ( overrides ) > maxOverrides || len ( sources ) + len ( overrides ) > limits . sources {
return nil , cloneSourceInfos ( sources ) , [ ] Diagnostic { {
Code : CodeOverrideLimitExceeded , Severity : SeverityError ,
Message : "configuration overrides exceed the record or source-count limit" ,
} }
}
var diagnostics [ ] Diagnostic
for index , override := range overrides {
if ! validOverrideLabel ( override . Flag ) {
diagnostics = append ( diagnostics , Diagnostic {
Code : CodeOverrideInvalidLabel , Severity : SeverityError ,
Message : "override record " + strconv . Itoa ( index + 1 ) + " requires a safe nonempty flag name" ,
} )
}
}
if len ( diagnostics ) != 0 {
return nil , cloneSourceInfos ( sources ) , canonicalDiagnostics ( diagnostics )
}
prepared := make ( [ ] preparedOverride , len ( overrides ) )
allSources := cloneSourceInfos ( sources )
for index , override := range overrides {
sourceID := "source-" + strconv . Itoa ( len ( sources ) + index + 1 )
info := SourceInfo { ID : sourceID , Label : override . Flag , Layer : LayerCLI }
allSources = append ( allSources , info )
prepared [ index ] . source = info
}
seen := make ( map [ string ] int , len ( overrides ) )
pathAccepted := make ( [ ] bool , len ( overrides ) )
var usedBytes int64
usedNodes := 0
for index , override := range overrides {
location := & Location { SourceID : prepared [ index ] . source . ID }
if issue := validateOverridePath ( override . Path , base . root ) ; issue != nil {
issue . Primary = location
diagnostics = append ( diagnostics , * issue )
continue
}
pointer := override . Path . String ( )
if previous , duplicate := seen [ pointer ] ; duplicate {
diagnostics = append ( diagnostics , Diagnostic {
Code : CodeOverrideDuplicate , Severity : SeverityError , Path : override . Path . clone ( ) ,
Message : "configuration override path is repeated" , Primary : location ,
Related : [ ] Location { { SourceID : prepared [ previous ] . source . ID } } ,
} )
continue
}
seen [ pointer ] = index
if conflicting := overlappingOverride ( overrides [ : index ] , pathAccepted [ : index ] , override . Path ) ; conflicting >= 0 {
diagnostics = append ( diagnostics , Diagnostic {
Code : CodeOverrideOverlap , Severity : SeverityError , Path : override . Path . clone ( ) ,
Message : "configuration override paths overlap" , Primary : location ,
Related : [ ] Location { { SourceID : prepared [ conflicting ] . source . ID } } ,
} )
continue
}
if rule != nil && ( pathContains ( override . Path , rule . Path ) || pathContains ( rule . Path , override . Path ) ) {
diagnostics = append ( diagnostics , Diagnostic {
Code : CodeOverrideVersion , Severity : SeverityError , Path : override . Path . clone ( ) ,
Message : "configuration overrides cannot replace the schema-version path" , Primary : location ,
} )
continue
}
if pathContainsDirective ( override . Path ) {
diagnostics = append ( diagnostics , Diagnostic {
Code : CodeOverrideDirective , Severity : SeverityError , Path : override . Path . clone ( ) ,
Message : "configuration overrides cannot create configuration directives" , Primary : location ,
} )
continue
}
pathAccepted [ index ] = true
builder := overrideValueBuilder { sourceID : prepared [ index ] . source . ID , active : make ( map [ valueVisit ] bool ) }
value , issue := builder . build ( override . Value , override . Path , len ( override . Path . segments ) )
if issue != nil {
issue . Primary = location
diagnostics = append ( diagnostics , * issue )
continue
}
if relative , ok := overrideDirectivePath ( value , Path { } ) ; ok {
diagnostics = append ( diagnostics , Diagnostic {
Code : CodeOverrideDirective , Severity : SeverityError , Path : appendOverridePath ( override . Path , relative ) ,
Message : "configuration overrides cannot create configuration directives" , Primary : location ,
} )
continue
}
nodes := builder . nodes + len ( override . Path . segments ) * 2
if nodes > limits . nodes || base . inputNodes + usedNodes + nodes > limits . nodes {
diagnostics = append ( diagnostics , Diagnostic {
Code : CodeOverrideLimitExceeded , Severity : SeverityError , Path : override . Path . clone ( ) ,
Message : "configuration overrides exceed the aggregate node limit" , Primary : location ,
} )
continue
}
if builder . bytes > maxSourceBytes || base . inputBytes + usedBytes + builder . bytes > limits . bytes {
diagnostics = append ( diagnostics , Diagnostic {
Code : CodeOverrideLimitExceeded , Severity : SeverityError , Path : override . Path . clone ( ) ,
Message : "configuration overrides exceed a record or aggregate string-byte limit" , Primary : location ,
} )
continue
}
prepared [ index ] . path = override . Path . clone ( )
prepared [ index ] . value = value
prepared [ index ] . bytes = builder . bytes
prepared [ index ] . nodes = nodes
usedBytes += builder . bytes
usedNodes += nodes
}
if len ( diagnostics ) != 0 {
return nil , allSources , canonicalDiagnostics ( diagnostics )
}
result := cloneComposedDocument ( base )
for _ , override := range prepared {
applyPreparedOverride ( result , override )
}
result . inputBytes += usedBytes
result . inputNodes += usedNodes
return result , allSources , nil
}
func validOverrideLabel ( label string ) bool {
if label == "" || strings . TrimSpace ( label ) != label || ! utf8 . ValidString ( label ) {
return false
}
for _ , character := range label {
if unicode . IsControl ( character ) {
return false
}
}
return true
}
func validateOverridePath ( path Path , root * document . Node ) * Diagnostic {
if ! path . valid ( ) || len ( path . segments ) == 0 {
return & Diagnostic { Code : CodeOverrideInvalidPath , Severity : SeverityError , Path : path . clone ( ) , Message : "configuration override path must be a valid non-root mapping path" }
}
current := root
for index , segment := range path . segments {
if segment . kind == pathSegmentIndex {
return & Diagnostic { Code : CodeOverrideInvalidPath , Severity : SeverityError , Path : path . clone ( ) , Message : "configuration override paths cannot contain sequence indices" }
}
if current == nil {
continue
}
if current . Kind != document . Mapping {
return & Diagnostic { Code : CodeOverrideInvalidPath , Severity : SeverityError , Path : path . clone ( ) , Message : "configuration override path traverses a non-mapping value" }
}
position := documentEntryIndex ( current . Mapping , segment . key )
if index == len ( path . segments ) - 1 {
continue
}
if position < 0 {
current = nil
continue
}
current = current . Mapping [ position ] . Value
}
return nil
}
func overlappingOverride ( previous [ ] Override , valid [ ] bool , path Path ) int {
for index , override := range previous {
if valid [ index ] && ( pathContains ( override . Path , path ) || pathContains ( path , override . Path ) ) {
return index
}
}
return - 1
}
func pathContainsDirective ( path Path ) bool {
for _ , segment := range path . segments {
if segment . key == "_configkit" {
return true
}
}
return false
}
func appendOverridePath ( base , relative Path ) Path {
result := base . clone ( )
result . segments = append ( result . segments , clonePathSegments ( relative . segments , 0 ) ... )
return result
}
func overrideDirectivePath ( node * document . Node , path Path ) ( Path , bool ) {
if node . Kind == document . Mapping {
for _ , entry := range node . Mapping {
child := path . Key ( entry . Key )
if entry . Key == "_configkit" {
return child , true
}
if found , ok := overrideDirectivePath ( entry . Value , child ) ; ok {
return found , true
}
}
} else if node . Kind == document . Sequence {
for index , child := range node . Sequence {
if found , ok := overrideDirectivePath ( child , path . Index ( index ) ) ; ok {
return found , true
}
}
}
return Path { } , false
}
func ( b * overrideValueBuilder ) build ( value any , path Path , depth int ) ( * document . Node , * Diagnostic ) {
if depth > maxDocumentDepth {
return nil , overrideValueDiagnostic ( CodeOverrideLimitExceeded , path , "configuration override exceeds the depth limit" )
}
b . nodes ++
if b . nodes > maxDocumentNodes {
return nil , overrideValueDiagnostic ( CodeOverrideLimitExceeded , path , "configuration override exceeds the node limit" )
}
location := document . Location { SourceID : b . sourceID }
switch value := value . ( type ) {
case nil :
return & document . Node { Kind : document . Null , Location : location } , nil
case string :
if ! b . addBytes ( len ( value ) ) {
return nil , overrideValueDiagnostic ( CodeOverrideLimitExceeded , path , "configuration override exceeds the record string-byte limit" )
}
return & document . Node { Kind : document . String , Text : value , Location : location } , nil
case bool :
return & document . Node { Kind : document . Boolean , Text : strconv . FormatBool ( value ) , Location : location } , nil
case int :
return overrideNumber ( strconv . FormatInt ( int64 ( value ) , 10 ) , location ) , nil
case int8 :
return overrideNumber ( strconv . FormatInt ( int64 ( value ) , 10 ) , location ) , nil
case int16 :
return overrideNumber ( strconv . FormatInt ( int64 ( value ) , 10 ) , location ) , nil
case int32 :
return overrideNumber ( strconv . FormatInt ( int64 ( value ) , 10 ) , location ) , nil
case int64 :
return overrideNumber ( strconv . FormatInt ( value , 10 ) , location ) , nil
case uint :
return overrideNumber ( strconv . FormatUint ( uint64 ( value ) , 10 ) , location ) , nil
case uint8 :
return overrideNumber ( strconv . FormatUint ( uint64 ( value ) , 10 ) , location ) , nil
case uint16 :
return overrideNumber ( strconv . FormatUint ( uint64 ( value ) , 10 ) , location ) , nil
case uint32 :
return overrideNumber ( strconv . FormatUint ( uint64 ( value ) , 10 ) , location ) , nil
case uint64 :
return overrideNumber ( strconv . FormatUint ( value , 10 ) , location ) , nil
case float32 :
if math . IsNaN ( float64 ( value ) ) || math . IsInf ( float64 ( value ) , 0 ) {
return nil , overrideValueDiagnostic ( CodeOverrideInvalidValue , path , "configuration override float must be finite" )
}
return overrideNumber ( strconv . FormatFloat ( float64 ( value ) , 'g' , - 1 , 32 ) , location ) , nil
case float64 :
if math . IsNaN ( value ) || math . IsInf ( value , 0 ) {
return nil , overrideValueDiagnostic ( CodeOverrideInvalidValue , path , "configuration override float must be finite" )
}
return overrideNumber ( strconv . FormatFloat ( value , 'g' , - 1 , 64 ) , location ) , nil
case [ ] any :
if value == nil {
return & document . Node { Kind : document . Null , Location : location } , nil
}
leave , diagnostic := b . enter ( reflect . ValueOf ( value ) , path )
if diagnostic != nil {
return nil , diagnostic
}
defer leave ( )
if len ( value ) > maxDocumentNodes - b . nodes {
return nil , overrideValueDiagnostic ( CodeOverrideLimitExceeded , path , "configuration override exceeds the node limit" )
}
node := & document . Node { Kind : document . Sequence , Location : location , Sequence : make ( [ ] * document . Node , len ( value ) ) }
for index , child := range value {
built , diagnostic := b . build ( child , path . Index ( index ) , depth + 1 )
if diagnostic != nil {
return nil , diagnostic
}
node . Sequence [ index ] = built
}
return node , nil
case map [ string ] any :
if value == nil {
return & document . Node { Kind : document . Null , Location : location } , nil
}
leave , diagnostic := b . enter ( reflect . ValueOf ( value ) , path )
if diagnostic != nil {
return nil , diagnostic
}
defer leave ( )
if len ( value ) > ( maxDocumentNodes - b . nodes ) / 2 {
return nil , overrideValueDiagnostic ( CodeOverrideLimitExceeded , path , "configuration override exceeds the node limit" )
}
keys := make ( [ ] string , 0 , len ( value ) )
for key := range value {
keys = append ( keys , key )
}
slices . Sort ( keys )
node := & document . Node { Kind : document . Mapping , Location : location , Mapping : make ( [ ] document . Entry , 0 , len ( keys ) ) }
for _ , key := range keys {
b . nodes ++ // mapping key
if ! b . addBytes ( len ( key ) ) {
return nil , overrideValueDiagnostic ( CodeOverrideLimitExceeded , path . Key ( key ) , "configuration override exceeds the record string-byte limit" )
}
built , diagnostic := b . build ( value [ key ] , path . Key ( key ) , depth + 1 )
if diagnostic != nil {
return nil , diagnostic
}
node . Mapping = append ( node . Mapping , document . Entry { Key : key , KeyLocation : location , ValueLocation : location , Value : built } )
}
return node , nil
default :
return nil , overrideValueDiagnostic ( CodeOverrideInvalidValue , path , "configuration override value has an unsupported type" )
}
}
func ( b * overrideValueBuilder ) addBytes ( count int ) bool {
if count < 0 || int64 ( count ) > maxSourceBytes - b . bytes {
return false
}
b . bytes += int64 ( count )
return true
}
func ( b * overrideValueBuilder ) enter ( value reflect . Value , path Path ) ( func ( ) , * Diagnostic ) {
visit , ok := visitFor ( value )
if ! ok {
return func ( ) { } , nil
}
if b . active [ visit ] {
return nil , overrideValueDiagnostic ( CodeOverrideInvalidValue , path , "configuration override values must not contain cycles" )
}
b . active [ visit ] = true
return func ( ) { delete ( b . active , visit ) } , nil
}
func overrideValueDiagnostic ( code Code , path Path , message string ) * Diagnostic {
return & Diagnostic { Code : code , Severity : SeverityError , Path : path . clone ( ) , Message : message }
}
func overrideNumber ( text string , location document . Location ) * document . Node {
return & document . Node { Kind : document . Number , Text : text , Location : location }
}
func cloneComposedDocument ( base * composedDocument ) * composedDocument {
return & composedDocument {
root : document . Clone ( base . root ) , claims : cloneCompositionClaims ( base . claims ) ,
origins : cloneOriginIndex ( base . origins ) , overlays : cloneOverlayRecords ( base . overlays ) ,
2026-09-06 22:14:54 +00:00
applications : cloneHistoryApplications ( base . applications ) ,
inputBytes : base . inputBytes , inputNodes : base . inputNodes ,
2026-09-06 21:55:35 +00:00
}
}
func applyPreparedOverride ( result * composedDocument , override preparedOverride ) {
location := document . Location { SourceID : override . source . ID }
mergeOverlayOrigin ( result . origins , Path { } , location , LayerCLI )
current := result . root
currentPath := Path { }
for index , segment := range override . path . segments {
path := currentPath . Key ( segment . key )
position := documentEntryIndex ( current . Mapping , segment . key )
if index < len ( override . path . segments ) - 1 {
if position < 0 {
child := & document . Node { Kind : document . Mapping , Location : location , Mapping : [ ] document . Entry { } }
current . Mapping = append ( current . Mapping , document . Entry { Key : segment . key , KeyLocation : location , ValueLocation : location , Value : child } )
collectOverlayOrigins ( result . origins , child , path , LayerCLI )
current = child
} else {
current = current . Mapping [ position ] . Value
mergeOverlayOrigin ( result . origins , path , location , LayerCLI )
}
currentPath = path
continue
}
previous := cloneOrigin ( result . origins [ path . String ( ) ] )
var displaced [ ] displacedDefinition
var before * document . Node
if position < 0 {
incoming := document . Clone ( override . value )
current . Mapping = append ( current . Mapping , document . Entry { Key : segment . key , KeyLocation : location , ValueLocation : location , Value : incoming } )
collectOverlayOrigins ( result . origins , incoming , path , LayerCLI )
} else {
existing := current . Mapping [ position ] . Value
before = document . Clone ( existing )
displaced = affectedOverrideOrigins ( existing , override . value , result . origins , path )
if existing . Kind == document . Mapping && override . value . Kind == document . Mapping {
mergeOverlayOrigin ( result . origins , path , location , LayerCLI )
mergeOverlayMappings ( result , existing , override . value , path , LayerCLI , false )
} else {
deleteOriginSubtree ( result . origins , path )
current . Mapping [ position ] = document . Entry { Key : segment . key , KeyLocation : location , ValueLocation : location , Value : document . Clone ( override . value ) }
collectOverlayOrigins ( result . origins , current . Mapping [ position ] . Value , path , LayerCLI )
}
}
position = documentEntryIndex ( current . Mapping , segment . key )
result . overlays = append ( result . overlays , overlayRecord { change : Change {
Path : path . clone ( ) , Origin : overlayOrigin ( LayerCLI , location ) , Previous : previousOrigins ( previous ) ,
} , displaced : displaced , before : before , after : document . Clone ( current . Mapping [ position ] . Value ) } )
2026-09-06 22:14:54 +00:00
result . applications = append ( result . applications , historyApplication {
layer : LayerCLI , path : path . clone ( ) , value : override . value ,
origin : overlayOrigin ( LayerCLI , location ) ,
} )
2026-09-06 21:55:35 +00:00
}
}
func affectedOverrideOrigins ( existing , incoming * document . Node , origins map [ string ] Origin , path Path ) [ ] displacedDefinition {
displaced := [ ] displacedDefinition { { path : path . clone ( ) , origin : cloneOrigin ( origins [ path . String ( ) ] ) } }
if existing . Kind == document . Mapping && incoming . Kind == document . Mapping {
for _ , entry := range incoming . Mapping {
position := documentEntryIndex ( existing . Mapping , entry . Key )
if position < 0 {
continue
}
childPath := path . Key ( entry . Key )
childExisting := existing . Mapping [ position ] . Value
if childExisting . Kind == document . Mapping && entry . Value . Kind == document . Mapping {
displaced = append ( displaced , affectedOverrideOrigins ( childExisting , entry . Value , origins , childPath ) ... )
} else {
displaced = append ( displaced , displacedOrigins ( childExisting , origins , childPath ) ... )
}
}
} else {
displaced = displacedOrigins ( existing , origins , path )
}
slices . SortFunc ( displaced , func ( left , right displacedDefinition ) int {
return strings . Compare ( left . path . String ( ) , right . path . String ( ) )
} )
return displaced
}