|
|
|
|
@@ -28,6 +28,13 @@ type sequenceIdentityRecord struct {
|
|
|
|
|
location document.Location
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type sequenceIdentityContext uint8
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
sequenceStructuralRecord sequenceIdentityContext = iota
|
|
|
|
|
sequencePayloadRecord
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// normalizeSequenceIdentityFields treats identity field names as a set.
|
|
|
|
|
func normalizeSequenceIdentityFields(fields []string) ([]string, error) {
|
|
|
|
|
if len(fields) == 0 {
|
|
|
|
|
@@ -150,21 +157,21 @@ func sequenceIdentityTuple(values []*document.Node) (string, error) {
|
|
|
|
|
return encoded.String(), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// sequenceMappingIndex is built once per record. Structural fields are omitted
|
|
|
|
|
// by entry index, so a directive is excluded only at its actual occurrence.
|
|
|
|
|
// sequenceMappingIndex is built once per record. Structural lookup excludes the
|
|
|
|
|
// directive's occurrence; effective payload and reference mappings keep all keys.
|
|
|
|
|
type sequenceMappingIndex struct {
|
|
|
|
|
entries []document.Entry
|
|
|
|
|
byKey map[string]int
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func newSequenceMappingIndex(record *document.Node) sequenceMappingIndex {
|
|
|
|
|
func newSequenceMappingIndex(record *document.Node, context sequenceIdentityContext) sequenceMappingIndex {
|
|
|
|
|
index := sequenceMappingIndex{byKey: make(map[string]int)}
|
|
|
|
|
if record == nil || record.Kind != document.Mapping {
|
|
|
|
|
return index
|
|
|
|
|
}
|
|
|
|
|
index.entries = record.Mapping
|
|
|
|
|
directiveIndex := -1
|
|
|
|
|
if directive, exists := inheritanceDirective(record); exists {
|
|
|
|
|
if directive, exists := inheritanceDirective(record); context == sequenceStructuralRecord && exists {
|
|
|
|
|
for entryIndex := range record.Mapping {
|
|
|
|
|
if record.Mapping[entryIndex].Key == directive.Key && record.Mapping[entryIndex].KeyLocation == directive.KeyLocation {
|
|
|
|
|
directiveIndex = entryIndex
|
|
|
|
|
@@ -227,10 +234,10 @@ func validateSequenceIdentityFrom(sequence *document.Node, path Path, fields []s
|
|
|
|
|
}
|
|
|
|
|
return nil, []Diagnostic{{Code: codes.invalid, Severity: SeverityError, Path: path, Message: "sequence identity requires at least one field", Primary: location}}
|
|
|
|
|
}
|
|
|
|
|
return validateNormalizedSequenceIdentityFrom(sequence, path, normalized, codes, startIndex)
|
|
|
|
|
return validateNormalizedSequenceIdentityFrom(sequence, path, normalized, codes, startIndex, sequenceStructuralRecord)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func validateNormalizedSequenceIdentityFrom(sequence *document.Node, path Path, normalized []string, codes sequenceIdentityDiagnosticCodes, startIndex int) (map[string]sequenceIdentityRecord, []Diagnostic) {
|
|
|
|
|
func validateNormalizedSequenceIdentityFrom(sequence *document.Node, path Path, normalized []string, codes sequenceIdentityDiagnosticCodes, startIndex int, context sequenceIdentityContext) (map[string]sequenceIdentityRecord, []Diagnostic) {
|
|
|
|
|
if sequence == nil || sequence.Kind != document.Sequence {
|
|
|
|
|
location := (*Location)(nil)
|
|
|
|
|
if sequence != nil {
|
|
|
|
|
@@ -251,7 +258,7 @@ func validateNormalizedSequenceIdentityFrom(sequence *document.Node, path Path,
|
|
|
|
|
}
|
|
|
|
|
return nil, []Diagnostic{{Code: codes.invalid, Severity: SeverityError, Path: itemPath, Message: "identified collection items must be mappings", Primary: primary}}
|
|
|
|
|
}
|
|
|
|
|
mapping := newSequenceMappingIndex(item)
|
|
|
|
|
mapping := newSequenceMappingIndex(item, context)
|
|
|
|
|
tuple, locations, missing, entryIndex := mapping.identity(normalized)
|
|
|
|
|
if entryIndex == -1 {
|
|
|
|
|
location := publicLocation(item.Location)
|
|
|
|
|
|