cue-lang / docs-and-content

A place to discuss, plan, and track documentation on cuelang.org
5 stars 1 forks source link

docs/concept/understanding-difference-between-cue-definitions-and-close-function: Understanding the difference between CUE definitions and the close function #119

Open jpluscplusm opened 2 months ago

jpluscplusm commented 2 months ago

From Slack: https://cuelang.slack.com/archives/CLT4FD7KP/p1708102852448829

Original thread #### David Desmarais-Michaud Hi, I am a newer comer to Cue, long time lurker, but first time user. One of the things that is stumping me is that I want to use cue to do strict validation for a helm chart values spec we are working on. I want to describe my spec in cue: ```cue app: { name: string } ``` And validate the values.yaml ```yaml name: true # error when validating with cue ``` However when running cue vet I want to be able to detect unknown properties. Such that if the user makes a spelling error in a property name, that property would be raised as unknown. I haven't found the write keyword search to figure this out yet... Thanks in advance!!! Happy to be here! 27 replies #### cwp You could use the close function on your app definition. That would make fields that are not explicitly defined generate an error. #### cwp ```cue app: close({ name: string }) ``` #### David Desmarais-Michaud Awesome! That's what I want. Can I close the definition of the entire cue file? And can close be recursive? #### cwp AFAIK, no and no. #### David Desmarais-Michaud I suppose the former is simply: ```cue close({ app: close({...}) }) ``` but its would have been great to close everything below it #### eloip Hum, this seems to be the typical use for [Definitions](https://cuelang.org/docs/references/spec/#definitions-and-hidden-fields): with `#app: { name: string }` , any further reference of #app can only refine its fields but not create new ones, thus catching typos. note that the `#app:` object itself is not closed (you can, `#app: { foo: int }` to add valid fields) Also, if the reference is an embedding, `{ #app, bar: string }`, it is considered as an extension of `#app:` so it's for schema definition, use `values: #app & config` to validate. AFAIK... (edited) #### cwp Indeed. With a definition, it’d be something like this: ```cue package example #App: { name: string } _yamlData: _ app: #App & _yamlData ``` Then you’d have to export with something like `cue export :example -l _yamlData: yaml: app.yaml` That’s pretty finicky though, might take some trial and error. Using close is probably easier. :smile: #### eloip yes! it will depend on "how" values are unified in the end. I'm not so familiar with the `-l` flags and path syntax in the CLI, is that a heritage from Go ? #### cwp :shrug: #### David Desmarais-Michaud It seems to me, that if I want to do closed schema validation my best bet is to define all my types as `#Definitions` and and close my top level: ```cue #app: { ... } #database: { ... } close({ app: #app database: #database }) ``` Any thoughts on this approach? (edited) Also if anybody can help me understand the value in having package declarations as if it was a Go package that would be great but unrelated :slightly_smiling_face: #### cwp That looks good! The package declaration groups together all the files with that declaration, so you can do eg `cue vet :examplePackge`. You can also import other packages, so it’s a good way to organize and structure your code. #### myitcv This is a good thread for a concept guide/tutorial to my mind! Just following up on a few points here with an example using cue vet ``` exec cue vet -d '#schema' x.cue ok.yaml ! exec cue vet -d '#schema' x.cue bad.yaml cmp stderr stderr.golden -- bad.yaml -- app: name: test database: name: test other: name: test -- ok.yaml -- app: name: test database: name: test -- x.cue -- #schema: { app: #app database: #database } #app: { name?: string } #database: { name?: string } -- stderr.golden -- other: field not allowed: ./bad.yaml:7:1 ./x.cue:1:10 ``` Whilst `close()` is not recursive, referring to a definition does recursively close the everything "contained" within the value, unless it is explicitly left open via `...` The use of the -d flag to cue vet allows me to refer to the schema that I want to use for validation And if that is reference to a definition, the result will be recursively closed #### David Desmarais-Michaud Yeah I didn't get that definitions were recursively closed at first, but I figured it out along the way. I love it, and love the `...` syntax to open the definitions. Closed first is a great model.

Content

A concept guide that explains the different results achieved when using a definition versus explicit close() calls.

Audience

A CUE-aware beginner.