this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

encoding/jsonschema: avoid unnecessary alias to root

Issue #3354 demonstrates that aliases are used when they're
not actually needed. When investigating the fix for #2287, I
realised where the problem might be, and this is the result.

The problem was that all the self-references need to reference
the same AST node, but they were not doing so. Fix that by
creating the struct node to be embedded when we know that
we need a self-reference. We can also use the presence of
that node to signal that a self-reference is needed, removing the
need for `hasSelfReference`.

Fixes #3354

Signed-off-by: Roger Peppe <rogpeppe@gmail.com>
Change-Id: Ie886b5819c612cbd64abca62d3231aedd530e2bf
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1199626
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>

+42 -54
+32 -11
encoding/jsonschema/decode.go
··· 44 44 errs errors.Error 45 45 numID int // for creating unique numbers: increment on each use 46 46 mapURLErrors map[string]bool 47 + // self holds the struct literal that will eventually be embedded 48 + // in the top level file. It is only set when decoder.rootRef is 49 + // called. 50 + self *ast.StructLit 47 51 } 48 52 49 53 // addImport registers ··· 169 173 expr = ast.NewStruct(ref[i], expr) 170 174 } 171 175 172 - if root.hasSelfReference { 173 - return []ast.Decl{ 174 - &ast.EmbedDecl{Expr: ast.NewIdent(topSchema)}, 175 - &ast.Field{ 176 - Label: ast.NewIdent(topSchema), 177 - Value: &ast.StructLit{Elts: a}, 178 - }, 179 - } 176 + if root.self == nil { 177 + return a 178 + } 179 + root.self.Elts = a 180 + return []ast.Decl{ 181 + &ast.EmbedDecl{Expr: d.rootRef()}, 182 + &ast.Field{ 183 + Label: d.rootRef(), 184 + Value: root.self, 185 + }, 180 186 } 187 + } 181 188 182 - return a 189 + // rootRef returns a reference to the top of the file. We do this by 190 + // creating a helper schema: 191 + // 192 + // _schema: {...} 193 + // _schema 194 + // 195 + // This is created at the finalization stage, signaled by d.self being 196 + // set, which rootRef does as a side-effect. 197 + func (d *decoder) rootRef() *ast.Ident { 198 + ident := ast.NewIdent("_schema") 199 + if d.self == nil { 200 + d.self = &ast.StructLit{} 201 + } 202 + // Ensure that all self-references refer to the same node. 203 + ident.Node = d.self 204 + return ident 183 205 } 184 206 185 207 func (d *decoder) errf(n cue.Value, format string, args ...interface{}) ast.Expr { ··· 363 385 definitions []ast.Decl 364 386 365 387 // Used for inserting definitions, properties, etc. 366 - hasSelfReference bool 367 - obj *ast.StructLit 388 + obj *ast.StructLit 368 389 // Complete at finalize. 369 390 fieldRefs map[label]refs 370 391
+4 -23
encoding/jsonschema/ref.go
··· 89 89 return u 90 90 } 91 91 92 - const topSchema = "_schema" 93 - 94 92 // makeCUERef converts a URI into a CUE reference for the current location. 95 93 // The returned identifier (or first expression in a selection chain), is 96 94 // hardwired to point to the resolved value. This will allow astutil.Sanitize ··· 136 134 case u.Host == "" && u.Path == "", 137 135 s.id != nil && s.id.Host == u.Host && s.id.Path == u.Path: 138 136 if len(fragmentParts) == 0 { 139 - // refers to the top of the file. We will allow this by 140 - // creating a helper schema as such: 141 - // _schema: {...} 142 - // _schema 143 - // This is created at the finalization stage if 144 - // hasSelfReference is set. 145 - s.hasSelfReference = true 146 - 147 - ident = ast.NewIdent(topSchema) 148 - ident.Node = s.obj 149 - return ident 137 + // Refers to the top of the file. 138 + return s.rootRef() 150 139 } 151 140 152 141 ident, fragmentParts = s.getNextIdent(n, fragmentParts) ··· 202 191 // state above the root state that we need to update. 203 192 s = s.up 204 193 205 - // refers to the top of the file. We will allow this by 206 - // creating a helper schema as such: 207 - // _schema: {...} 208 - // _schema 209 - // This is created at the finalization stage if 210 - // hasSelfReference is set. 211 - s.hasSelfReference = true 212 - ident = ast.NewIdent(topSchema) 213 - ident.Node = s.obj 214 - return ident 194 + // Refers to the top of the file. 195 + return s.rootRef() 215 196 } 216 197 217 198 x := s.idRef[0]
+4 -14
encoding/jsonschema/testdata/issue3351.txtar
··· 70 70 @jsonschema(id="https://www.sourcemeta.com/schemas/vendor/json-e@1.json") 71 71 $else?: #["jsone-value"] 72 72 $let?: [string]: null | bool | number | string | [...] | { 73 - [string]: _schema_1 73 + [string]: _schema 74 74 } 75 - $sort?: _schema_5 | [...number] 75 + $sort?: _schema | [...number] 76 76 {[!~"^($else|$let|$sort)$"]: #["jsone-value"]} 77 77 78 - #: "jsone-value": _schema_A | [..._schema_8] 78 + #: "jsone-value": _schema | [..._schema] 79 79 80 80 #: "jsone-array": [...#["jsone-value"]] 81 81 82 - #: "jsone-object-array": [..._schema_E] 82 + #: "jsone-object-array": [..._schema] 83 83 } 84 - 85 - let _schema_1 = _schema 86 - 87 - let _schema_5 = _schema 88 - 89 - let _schema_A = _schema 90 - 91 - let _schema_8 = _schema 92 - 93 - let _schema_E = _schema
+1 -3
encoding/jsonschema/testdata/refroot.txtar
··· 19 19 null | bool | number | string | [...] | { 20 20 @jsonschema(id="http://cuelang.org/go/encoding/openapi/testdata/order.json") 21 21 value?: _ 22 - next?: _schema_1 22 + next?: _schema 23 23 ... 24 24 } 25 25 } 26 - 27 - let _schema_1 = _schema
+1 -3
encoding/jsonschema/testdata/refroot2.txtar
··· 16 16 @jsonschema(schema="http://json-schema.org/draft-07/schema#") 17 17 null | bool | number | string | [...] | { 18 18 value?: _ 19 - next?: _schema_1 19 + next?: _schema 20 20 ... 21 21 } 22 22 } 23 - 24 - let _schema_1 = _schema