package configkit // Layer identifies the precedence layer responsible for a configuration value. type Layer string const ( LayerDefault Layer = "default" LayerBase Layer = "base" LayerProfile Layer = "profile" LayerCLI Layer = "cli" LayerResolution Layer = "resolution" ) // ChangeKind identifies an application resolution operation. The zero value is // used for input and default origins. type ChangeKind string const ( ChangeDerivedDefault ChangeKind = "derived_default" ChangeNormalization ChangeKind = "normalization" ) // Severity classifies a diagnostic. type Severity string const ( SeverityError Severity = "error" SeverityWarning Severity = "warning" ) // Code is a stable, machine-readable diagnostic classification. type Code string const ( CodeSourceInvalid Code = "source.invalid" CodeSourceMissing Code = "source.missing" CodeSourcePermission Code = "source.permission" CodeSourceRead Code = "source.read" CodeSourceNotRegular Code = "source.not_regular" CodeSourceLimitExceeded Code = "source.limit_exceeded" CodeSourceReaderUsed Code = "source.reader_used" CodeYAMLInvalid Code = "yaml.invalid" CodeYAMLEmpty Code = "yaml.empty" CodeYAMLMultipleDocuments Code = "yaml.multiple_documents" CodeYAMLRootType Code = "yaml.root_type" CodeYAMLDuplicateKey Code = "yaml.duplicate_key" CodeYAMLTag Code = "yaml.tag" CodeYAMLAnchor Code = "yaml.anchor" CodeYAMLAlias Code = "yaml.alias" CodeYAMLMergeKey Code = "yaml.merge_key" CodeYAMLScalar Code = "yaml.scalar" CodeYAMLDepthLimit Code = "yaml.depth_limit" CodeYAMLNodeLimit Code = "yaml.node_limit" CodeSchemaRoot Code = "schema.root" CodeSchemaUnsupportedType Code = "schema.unsupported_type" CodeSchemaAmbiguousField Code = "schema.ambiguous_field" CodeSchemaTag Code = "schema.tag" CodeSchemaTextCodec Code = "schema.text_codec" CodeSchemaInline Code = "schema.inline" CodeSchemaCycle Code = "schema.cycle" CodeSchemaProjectionLimit Code = "schema.projection_limit" CodeSchemaCodec Code = "schema.codec" CodeSchemaNonFinite Code = "schema.non_finite" CodeSchemaDynamicType Code = "schema.dynamic_type" CodeDecodeType Code = "decode.type" CodeDecodeNull Code = "decode.null" CodeDecodeRange Code = "decode.range" CodeDecodeDuration Code = "decode.duration" CodeDecodeText Code = "decode.text" CodeDecodeUnknownField Code = "decode.unknown_field" CodeDecodeArrayLength Code = "decode.array_length" ) // Location identifies a position in a configuration source. Zero line and column // values mean that coordinates are unavailable or synthetic. type Location struct { SourceID string Line int Column int } // SourceInfo describes a source discovered during a load. Path is a canonical // local path when one exists. ImportedFrom identifies the declaration that // included this source. type SourceInfo struct { ID string Label string Path string Layer Layer ImportedFrom *Location } // Diagnostic is a safe structured problem report. Message and source labels must // never contain configuration values or other secrets. type Diagnostic struct { Code Code Severity Severity Path Path Message string Primary *Location Related []Location } // Origin describes where an effective definition came from. Multiple locations // represent a composite origin. type Origin struct { Layer Layer Locations []Location Operation ChangeKind } // FieldInfo describes an effective configuration path. type FieldInfo struct { Explicit bool Null bool Origin Origin } // Change describes a definition or application-resolution operation. Historical // values are intentionally not exposed by this record. type Change struct { Path Path Origin Origin Previous []Origin Reasons []string Dependencies []Path } func cloneLocation(location *Location) *Location { if location == nil { return nil } cloned := *location return &cloned } func cloneLocations(locations []Location) []Location { if locations == nil { return nil } return append([]Location(nil), locations...) } func cloneSourceInfo(source SourceInfo) SourceInfo { source.ImportedFrom = cloneLocation(source.ImportedFrom) return source } func cloneSourceInfos(sources []SourceInfo) []SourceInfo { if sources == nil { return nil } cloned := make([]SourceInfo, len(sources)) for i, source := range sources { cloned[i] = cloneSourceInfo(source) } return cloned } func cloneOrigin(origin Origin) Origin { origin.Locations = cloneLocations(origin.Locations) return origin } func cloneFieldInfo(info FieldInfo) FieldInfo { info.Origin = cloneOrigin(info.Origin) return info } func cloneChange(change Change) Change { change.Path = change.Path.clone() change.Origin = cloneOrigin(change.Origin) if change.Previous != nil { previous := make([]Origin, len(change.Previous)) for i, origin := range change.Previous { previous[i] = cloneOrigin(origin) } change.Previous = previous } change.Reasons = append([]string(nil), change.Reasons...) if change.Dependencies != nil { dependencies := make([]Path, len(change.Dependencies)) for i, path := range change.Dependencies { dependencies[i] = path.clone() } change.Dependencies = dependencies } return change } func cloneDiagnostic(diagnostic Diagnostic) Diagnostic { diagnostic.Path = diagnostic.Path.clone() diagnostic.Primary = cloneLocation(diagnostic.Primary) diagnostic.Related = cloneLocations(diagnostic.Related) return diagnostic } func cloneDiagnostics(diagnostics []Diagnostic) []Diagnostic { if diagnostics == nil { return nil } cloned := make([]Diagnostic, len(diagnostics)) for i, diagnostic := range diagnostics { cloned[i] = cloneDiagnostic(diagnostic) } return cloned }