| // Copyright 2025 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package jsonschema |
| |
| import "maps" |
| |
| // An annotations tracks certain properties computed by keywords that are used by validation. |
| // ("Annotation" is the spec's term.) |
| // In particular, the unevaluatedItems and unevaluatedProperties keywords need to know which |
| // items and properties were evaluated (validated successfully). |
| type annotations struct { |
| allItems bool // all items were evaluated |
| endIndex int // 1+largest index evaluated by prefixItems |
| evaluatedIndexes map[int]bool // set of indexes evaluated by contains |
| allProperties bool // all properties were evaluated |
| evaluatedProperties map[string]bool // set of properties evaluated by various keywords |
| } |
| |
| // noteIndex marks i as evaluated. |
| func (a *annotations) noteIndex(i int) { |
| if a.evaluatedIndexes == nil { |
| a.evaluatedIndexes = map[int]bool{} |
| } |
| a.evaluatedIndexes[i] = true |
| } |
| |
| // noteEndIndex marks items with index less than end as evaluated. |
| func (a *annotations) noteEndIndex(end int) { |
| if end > a.endIndex { |
| a.endIndex = end |
| } |
| } |
| |
| // noteProperty marks prop as evaluated. |
| func (a *annotations) noteProperty(prop string) { |
| if a.evaluatedProperties == nil { |
| a.evaluatedProperties = map[string]bool{} |
| } |
| a.evaluatedProperties[prop] = true |
| } |
| |
| // noteProperties marks all the properties in props as evaluated. |
| func (a *annotations) noteProperties(props map[string]bool) { |
| a.evaluatedProperties = merge(a.evaluatedProperties, props) |
| } |
| |
| // merge adds b's annotations to a. |
| // a must not be nil. |
| func (a *annotations) merge(b *annotations) { |
| if b == nil { |
| return |
| } |
| if b.allItems { |
| a.allItems = true |
| } |
| if b.endIndex > a.endIndex { |
| a.endIndex = b.endIndex |
| } |
| a.evaluatedIndexes = merge(a.evaluatedIndexes, b.evaluatedIndexes) |
| if b.allProperties { |
| a.allProperties = true |
| } |
| a.evaluatedProperties = merge(a.evaluatedProperties, b.evaluatedProperties) |
| } |
| |
| // merge adds t's keys to s and returns s. |
| // If s is nil, it returns a copy of t. |
| func merge[K comparable](s, t map[K]bool) map[K]bool { |
| if s == nil { |
| return maps.Clone(t) |
| } |
| maps.Copy(s, t) |
| return s |
| } |