feat(template): add token assertions and Schema.Info
- commit
- 6416d3eb3390fdffedc6d0d487ccfed8e7903d58
- author
- brice · · 2026-10-12 15:34 UTC
- committer
- brice · · 2026-10-12 16:17 UTC
- parent
- ee5c1ce
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +78 -0
A template/assert.go +68 -0
| @@ -0,0 +1,68 @@ | |||
| 1 | + | // SPDX-License-Identifier: MIT | |
| 2 | + | ||
| 3 | + | package template | |
| 4 | + | ||
| 5 | + | import "fmt" | |
| 6 | + | ||
| 7 | + | // TokenError is an error about a token, positioned at it. It is what the | |
| 8 | + | // Assert functions return. | |
| 9 | + | type TokenError struct { | |
| 10 | + | Token Token | |
| 11 | + | Message string | |
| 12 | + | } | |
| 13 | + | ||
| 14 | + | func (e *TokenError) Error() string { return e.Message } | |
| 15 | + | ||
| 16 | + | func assertErr(t Token, desc string, want string) error { | |
| 17 | + | return &TokenError{Token: t, Message: fmt.Sprintf("Unexpected type '%s' encountered while reading '%s'. The type '%s' was expected.", t.Kind(), desc, want)} | |
| 18 | + | } | |
| 19 | + | ||
| 20 | + | // AssertString returns t as a string token or a [*TokenError] worded like the | |
| 21 | + | // reference's "Unexpected type 'X' encountered while reading 'desc'". | |
| 22 | + | func AssertString(t Token, desc string) (*String, error) { | |
| 23 | + | if s, ok := t.(*String); ok { | |
| 24 | + | return s, nil | |
| 25 | + | } | |
| 26 | + | return nil, assertErr(t, desc, KindString.String()) | |
| 27 | + | } | |
| 28 | + | ||
| 29 | + | // AssertBoolean returns t as a boolean token or a [*TokenError]. | |
| 30 | + | func AssertBoolean(t Token, desc string) (*Boolean, error) { | |
| 31 | + | if s, ok := t.(*Boolean); ok { | |
| 32 | + | return s, nil | |
| 33 | + | } | |
| 34 | + | return nil, assertErr(t, desc, KindBoolean.String()) | |
| 35 | + | } | |
| 36 | + | ||
| 37 | + | // AssertNumber returns t as a number token or a [*TokenError]. | |
| 38 | + | func AssertNumber(t Token, desc string) (*Number, error) { | |
| 39 | + | if s, ok := t.(*Number); ok { | |
| 40 | + | return s, nil | |
| 41 | + | } | |
| 42 | + | return nil, assertErr(t, desc, KindNumber.String()) | |
| 43 | + | } | |
| 44 | + | ||
| 45 | + | // AssertSequence returns t as a sequence token or a [*TokenError]. | |
| 46 | + | func AssertSequence(t Token, desc string) (*Sequence, error) { | |
| 47 | + | if s, ok := t.(*Sequence); ok { | |
| 48 | + | return s, nil | |
| 49 | + | } | |
| 50 | + | return nil, assertErr(t, desc, KindSequence.String()) | |
| 51 | + | } | |
| 52 | + | ||
| 53 | + | // AssertMapping returns t as a mapping token or a [*TokenError]. | |
| 54 | + | func AssertMapping(t Token, desc string) (*Mapping, error) { | |
| 55 | + | if s, ok := t.(*Mapping); ok { | |
| 56 | + | return s, nil | |
| 57 | + | } | |
| 58 | + | return nil, assertErr(t, desc, KindMapping.String()) | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // AssertScalar returns t when it is neither a sequence nor a mapping, or a | |
| 62 | + | // [*TokenError]. | |
| 63 | + | func AssertScalar(t Token, desc string) (Token, error) { | |
| 64 | + | if IsScalar(t) { | |
| 65 | + | return t, nil | |
| 66 | + | } | |
| 67 | + | return nil, assertErr(t, desc, "ScalarToken") | |
| 68 | + | } | |
| @@ -0,0 +1,68 @@ | |||||
| 1 | + | // SPDX-License-Identifier: MIT | |||
| 2 | + | ||||
| 3 | + | package template | |||
| 4 | + | ||||
| 5 | + | import "fmt" | |||
| 6 | + | ||||
| 7 | + | // TokenError is an error about a token, positioned at it. It is what the | |||
| 8 | + | // Assert functions return. | |||
| 9 | + | type TokenError struct { | |||
| 10 | + | Token Token | |||
| 11 | + | Message string | |||
| 12 | + | } | |||
| 13 | + | ||||
| 14 | + | func (e *TokenError) Error() string { return e.Message } | |||
| 15 | + | ||||
| 16 | + | func assertErr(t Token, desc string, want string) error { | |||
| 17 | + | return &TokenError{Token: t, Message: fmt.Sprintf("Unexpected type '%s' encountered while reading '%s'. The type '%s' was expected.", t.Kind(), desc, want)} | |||
| 18 | + | } | |||
| 19 | + | ||||
| 20 | + | // AssertString returns t as a string token or a [*TokenError] worded like the | |||
| 21 | + | // reference's "Unexpected type 'X' encountered while reading 'desc'". | |||
| 22 | + | func AssertString(t Token, desc string) (*String, error) { | |||
| 23 | + | if s, ok := t.(*String); ok { | |||
| 24 | + | return s, nil | |||
| 25 | + | } | |||
| 26 | + | return nil, assertErr(t, desc, KindString.String()) | |||
| 27 | + | } | |||
| 28 | + | ||||
| 29 | + | // AssertBoolean returns t as a boolean token or a [*TokenError]. | |||
| 30 | + | func AssertBoolean(t Token, desc string) (*Boolean, error) { | |||
| 31 | + | if s, ok := t.(*Boolean); ok { | |||
| 32 | + | return s, nil | |||
| 33 | + | } | |||
| 34 | + | return nil, assertErr(t, desc, KindBoolean.String()) | |||
| 35 | + | } | |||
| 36 | + | ||||
| 37 | + | // AssertNumber returns t as a number token or a [*TokenError]. | |||
| 38 | + | func AssertNumber(t Token, desc string) (*Number, error) { | |||
| 39 | + | if s, ok := t.(*Number); ok { | |||
| 40 | + | return s, nil | |||
| 41 | + | } | |||
| 42 | + | return nil, assertErr(t, desc, KindNumber.String()) | |||
| 43 | + | } | |||
| 44 | + | ||||
| 45 | + | // AssertSequence returns t as a sequence token or a [*TokenError]. | |||
| 46 | + | func AssertSequence(t Token, desc string) (*Sequence, error) { | |||
| 47 | + | if s, ok := t.(*Sequence); ok { | |||
| 48 | + | return s, nil | |||
| 49 | + | } | |||
| 50 | + | return nil, assertErr(t, desc, KindSequence.String()) | |||
| 51 | + | } | |||
| 52 | + | ||||
| 53 | + | // AssertMapping returns t as a mapping token or a [*TokenError]. | |||
| 54 | + | func AssertMapping(t Token, desc string) (*Mapping, error) { | |||
| 55 | + | if s, ok := t.(*Mapping); ok { | |||
| 56 | + | return s, nil | |||
| 57 | + | } | |||
| 58 | + | return nil, assertErr(t, desc, KindMapping.String()) | |||
| 59 | + | } | |||
| 60 | + | ||||
| 61 | + | // AssertScalar returns t when it is neither a sequence nor a mapping, or a | |||
| 62 | + | // [*TokenError]. | |||
| 63 | + | func AssertScalar(t Token, desc string) (Token, error) { | |||
| 64 | + | if IsScalar(t) { | |||
| 65 | + | return t, nil | |||
| 66 | + | } | |||
| 67 | + | return nil, assertErr(t, desc, "ScalarToken") | |||
| 68 | + | } | |||
M template/definfo.go +10 -0
| @@ -117,3 +117,13 @@ func isDigits(s string) bool { | |||
| 117 | 117 | } | |
| 118 | 118 | return true | |
| 119 | 119 | } | |
| 120 | + | ||
| 121 | + | // Info returns the info of the schema definition called name, with the | |
| 122 | + | // contexts and functions that definition allows, or nil when there is none. | |
| 123 | + | func (s *Schema) Info(name string) *DefinitionInfo { | |
| 124 | + | d := s.definitions[name] | |
| 125 | + | if d == nil { | |
| 126 | + | return nil | |
| 127 | + | } | |
| 128 | + | return newDefinitionInfo(s, nil, d) | |
| 129 | + | } | |
| @@ -117,3 +117,13 @@ func isDigits(s string) bool { | |||||
| 117 | } | 117 | } | ||
| 118 | return true | 118 | return true | ||
| 119 | } | 119 | } | ||
| 120 | + | ||||
| 121 | + | // Info returns the info of the schema definition called name, with the | |||
| 122 | + | // contexts and functions that definition allows, or nil when there is none. | |||
| 123 | + | func (s *Schema) Info(name string) *DefinitionInfo { | |||
| 124 | + | d := s.definitions[name] | |||
| 125 | + | if d == nil { | |||
| 126 | + | return nil | |||
| 127 | + | } | |||
| 128 | + | return newDefinitionInfo(s, nil, d) | |||
| 129 | + | } | |||