Search code examples
cuelang

Checking the list for denied elements


I need validate list elements: list must contain required elements and must not contain forbidden elements. (In my example list - "cities")

I can check list for required elements with cue function list.Contains(). This function returns true , if element exists in list. And for checking list for forbidden elements I need something, acting vice versa.

I have to validate a big amount of conf files with cuelang. So first I convert them and merge to one common json file. And then run cue vet.

all_confs.json:

{
  "/tmp/europe.yml": {
    "raw": "conf:\n  iscontinent: true\n  cities: [\"Dehli\", \"Paris\"]\n\n",
    "structure": {
      "conf": {
        "iscontinent": true,
        "cities": [
          "Dehli",
          "Paris"
        ]
      }
    }
  },
  "/tmp/africa.yml": {
    "raw": "conf:\n  iscontinent: true\n  cities: [\"Addis-Abeba\", \"Nairobi\", \"Paris\"]\n  ",
    "structure": {
      "conf": {
        "iscontinent": true,
        "cities": [
          "Addis-Abeba",
          "Nairobi",
          "Paris"
        ]
      }
    }
  }
}

Rules file static_conf.cue:

package verifylist

import "list"

[=~"/tmp/africa.yml"]: structure!: conf!: {
  ...
// check for required elements - this works perfectly
  "cities"!: list.Contains("Nairobi") & list.Contains("Addis-Abeba")
}

How can I add check for forbidden element? In this example forbidden value is "Paris". May be there is some way to invert function result: true to false, false to true?

I find solution https://cuetorials.com/patterns/required-list-elem. But I couldn't apply it: I cannot refer list in .cue from .json. Is it possible? I also have rather big amount for forbidden element. And I wouldn't like to overload rules code with big amnount of cycles for each forbidden element.


Solution

  • The following CUE schema invalidates config when Paris is in the cities list:

    [=~"/tmp/africa.yml"]: structure!: conf!: {
      ...
      cities!: [for x in cities if x != "Paris" {x}]
    }
    

    The following schema invalidates config when Paris or London is in the cities list:

    [=~"/tmp/africa.yml"]: structure!: conf!: {
      ...
      cities!: [for x in cities if x != "Paris" && x != "London" {x}]
    }
    

    And also using the list module:

    import "list"
    
    forbidden_cities: ["Paris", "London"]
    
    [=~"/tmp/africa.yml"]: structure!: conf!: {
      ...
      cities!: [for x in cities if !list.Contains(forbidden_cities, x) {x}]
    }