github.com/hashicorp/hcl/v2@v2.20.0/cmd/hcldec/spec-format.md (about)

     1  # `hcldec` spec format
     2  
     3  The `hcldec` spec format instructs [`hcldec`](README.md) on how to validate
     4  one or more configuration files given in the HCL syntax and how to translate
     5  the result into JSON format.
     6  
     7  The spec format is itself built from HCL syntax, with each HCL block serving
     8  as a _spec_ whose block type and contents together describe a single mapping
     9  action and, in most cases, a validation constraint. Each spec block produces
    10  one JSON value.
    11  
    12  A spec _file_ must have a single top-level spec block that describes the
    13  top-level JSON value `hcldec` will return, and that spec block may have other
    14  nested spec blocks (depending on its type) that produce nested structures and
    15  additional validation constraints.
    16  
    17  The most common usage of `hcldec` is to produce a JSON object whose properties
    18  are derived from the top-level content of the input file. In this case, the
    19  root of the given spec file will have an `object` spec block whose contents
    20  describe how each of the object's properties are to be populated using
    21  nested spec blocks.
    22  
    23  Each spec is evaluated in the context of an HCL _body_, which is the HCL
    24  terminology for one level of nesting in a configuration file. The top-level
    25  objects in a file all belong to the root body of that file, and then each
    26  nested block has its own body containing the elements within that block.
    27  Some spec types select a new body as the context for their nested specs,
    28  allowing nested HCL structures to be decoded.
    29  
    30  ## Spec Block Types
    31  
    32  The following sections describe the different block types that can be used to
    33  define specs within a spec file.
    34  
    35  ### `object` spec blocks
    36  
    37  The `object` spec type is the most commonly used at the root of a spec file.
    38  Its result is a JSON object whose properties are set based on any nested
    39  spec blocks:
    40  
    41  ```hcl
    42  object {
    43    attr "name" {
    44      type = string
    45    }
    46    block "address" {
    47      object {
    48        attr "street" {
    49          type = string
    50        }
    51        # ...
    52      }
    53    }
    54  }
    55  ```
    56  
    57  Nested spec blocks inside `object` must always have an extra block label
    58  `"name"`, `"address"` and `"street"` in the above example) that specifies
    59  the name of the property that should be created in the JSON object result.
    60  This label also acts as a default name selector for the nested spec, allowing
    61  the `attr` blocks in the above example to omit the usually-required `name`
    62  argument in cases where the HCL input name and JSON output name are the same.
    63  
    64  An `object` spec block creates no validation constraints, but it passes on
    65  any validation constraints created by the nested specs.
    66  
    67  ### `array` spec blocks
    68  
    69  The `array` spec type produces a JSON array whose elements are set based on
    70  any nested spec blocks:
    71  
    72  ```hcl
    73  array {
    74    attr {
    75      name = "first_element"
    76      type = string
    77    }
    78    attr {
    79      name = "second_element"
    80      type = string
    81    }
    82  }
    83  ```
    84  
    85  An `array` spec block creates no validation constraints, but it passes on
    86  any validation constraints created by the nested specs.
    87  
    88  ### `attr` spec blocks
    89  
    90  The `attr` spec type reads the value of an attribute in the current body
    91  and returns that value as its result. It also creates validation constraints
    92  for the given attribute name and its value.
    93  
    94  ```hcl
    95  attr {
    96    name     = "document_root"
    97    type     = string
    98    required = true
    99  }
   100  ```
   101  
   102  `attr` spec blocks accept the following arguments:
   103  
   104  * `name` (required) - The attribute name to expect within the HCL input file.
   105    This may be omitted when a default name selector is created by a parent
   106    `object` spec, if the input attribute name should match the output JSON
   107    object property name.
   108  
   109  * `type` (optional) - A [type expression](#type-expressions) that the given
   110    attribute value must conform to. If this argument is set, `hcldec` will
   111    automatically convert the given input value to this type or produce an
   112    error if that is not possible.
   113  
   114  * `required` (optional) - If set to `true`, `hcldec` will produce an error
   115    if a value is not provided for the source attribute.
   116  
   117  `attr` is a leaf spec type, so no nested spec blocks are permitted.
   118  
   119  ### `block` spec blocks
   120  
   121  The `block` spec type applies one nested spec block to the contents of a
   122  block within the current body and returns the result of that spec. It also
   123  creates validation constraints for the given block type name.
   124  
   125  ```hcl
   126  block {
   127    block_type = "logging"
   128  
   129    object {
   130      attr "level" {
   131        type = string
   132      }
   133      attr "file" {
   134        type = string
   135      }
   136    }
   137  }
   138  ```
   139  
   140  `block` spec blocks accept the following arguments:
   141  
   142  * `block_type` (required) - The block type name to expect within the HCL
   143    input file. This may be omitted when a default name selector is created
   144    by a parent `object` spec, if the input block type name should match the
   145    output JSON object property name.
   146  
   147  * `required` (optional) - If set to `true`, `hcldec` will produce an error
   148    if a block of the specified type is not present in the current body.
   149  
   150  `block` creates a validation constraint that there must be zero or one blocks
   151  of the given type name, or exactly one if `required` is set.
   152  
   153  `block` expects a single nested spec block, which is applied to the body of
   154  the block of the given type when it is present.
   155  
   156  ### `block_list` spec blocks
   157  
   158  The `block_list` spec type is similar to `block`, but it accepts zero or
   159  more blocks of a specified type rather than requiring zero or one. The
   160  result is a JSON array with one entry per block of the given type.
   161  
   162  ```hcl
   163  block_list {
   164    block_type = "log_file"
   165  
   166    object {
   167      attr "level" {
   168        type = string
   169      }
   170      attr "filename" {
   171        type     = string
   172        required = true
   173      }
   174    }
   175  }
   176  ```
   177  
   178  `block_list` spec blocks accept the following arguments:
   179  
   180  * `block_type` (required) - The block type name to expect within the HCL
   181    input file. This may be omitted when a default name selector is created
   182    by a parent `object` spec, if the input block type name should match the
   183    output JSON object property name.
   184  
   185  * `min_items` (optional) - If set to a number greater than zero, `hcldec` will
   186    produce an error if fewer than the given number of blocks are present.
   187  
   188  * `max_items` (optional) - If set to a number greater than zero, `hcldec` will
   189    produce an error if more than the given number of blocks are present. This
   190    attribute must be greater than or equal to `min_items` if both are set.
   191  
   192  `block` creates a validation constraint on the number of blocks of the given
   193  type that must be present.
   194  
   195  `block` expects a single nested spec block, which is applied to the body of
   196  each matching block to produce the resulting list items.
   197  
   198  ### `block_set` spec blocks
   199  
   200  The `block_set` spec type behaves the same as `block_list` except that
   201  the result is in no specific order and any duplicate items are removed.
   202  
   203  ```hcl
   204  block_set {
   205    block_type = "log_file"
   206  
   207    object {
   208      attr "level" {
   209        type = string
   210      }
   211      attr "filename" {
   212        type     = string
   213        required = true
   214      }
   215    }
   216  }
   217  ```
   218  
   219  The contents of `block_set` are the same as for `block_list`.
   220  
   221  ### `block_map` spec blocks
   222  
   223  The `block_map` spec type is similar to `block`, but it accepts zero or
   224  more blocks of a specified type rather than requiring zero or one. The
   225  result is a JSON object, or possibly multiple nested JSON objects, whose
   226  properties are derived from the labels set on each matching block.
   227  
   228  ```hcl
   229  block_map {
   230    block_type = "log_file"
   231    labels = ["filename"]
   232  
   233    object {
   234      attr "level" {
   235        type     = string
   236        required = true
   237      }
   238    }
   239  }
   240  ```
   241  
   242  `block_map` spec blocks accept the following arguments:
   243  
   244  * `block_type` (required) - The block type name to expect within the HCL
   245    input file. This may be omitted when a default name selector is created
   246    by a parent `object` spec, if the input block type name should match the
   247    output JSON object property name.
   248  
   249  * `labels` (required) - A list of user-oriented block label names. Each entry
   250    in this list creates one level of object within the output value, and
   251    requires one additional block header label on any child block of this type.
   252    Block header labels are the quoted strings that appear after the block type
   253    name but before the opening `{`.
   254  
   255  `block` creates a validation constraint on the number of labels that blocks
   256  of the given type must have.
   257  
   258  `block` expects a single nested spec block, which is applied to the body of
   259  each matching block to produce the resulting map items.
   260  
   261  ## `block_attrs` spec blocks
   262  
   263  The `block_attrs` spec type is similar to an `attr` spec block of a map type,
   264  but it produces a map from the attributes of a block rather than from an
   265  attribute's expression.
   266  
   267  ```hcl
   268  block_attrs {
   269    block_type   = "variables"
   270    element_type = string
   271    required     = false
   272  }
   273  ```
   274  
   275  This allows a map with user-defined keys to be produced within block syntax,
   276  but due to the constraints of that syntax it also means that the user will
   277  be unable to dynamically-generate either individual key names using key
   278  expressions or the entire map value using a `for` expression.
   279  
   280  `block_attrs` spec blocks accept the following arguments:
   281  
   282  * `block_type` (required) - The block type name to expect within the HCL
   283    input file. This may be omitted when a default name selector is created
   284    by a parent `object` spec, if the input block type name should match the
   285    output JSON object property name.
   286  
   287  * `element_type` (required) - The value type to require for each of the
   288    attributes within a matched block. The resulting value will be a JSON
   289    object whose property values are of this type.
   290  
   291  * `required` (optional) - If `true`, an error will be produced if a block
   292    of the given type is not present. If `false` -- the default -- an absent
   293    block will be indicated by producing `null`.
   294  
   295  ## `literal` spec blocks
   296  
   297  The `literal` spec type returns a given literal value, and creates no
   298  validation constraints. It is most commonly used with the `default` spec
   299  type to create a fallback value, but can also be used e.g. to fill out
   300  required properties in an `object` spec that do not correspond to any
   301  construct in the input configuration.
   302  
   303  ```hcl
   304  literal {
   305    value = "hello world"
   306  }
   307  ```
   308  
   309  `literal` spec blocks accept the following argument:
   310  
   311  * `value` (required) - The value to return. This attribute may be an expression
   312    that uses [functions](#spec-definition-functions).
   313  
   314  `literal` is a leaf spec type, so no nested spec blocks are permitted.
   315  
   316  ## `default` spec blocks
   317  
   318  The `default` spec type evaluates a sequence of nested specs in turn and
   319  returns the result of the first one that produces a non-null value.
   320  It creates no validation constraints of its own, but passes on the validation
   321  constraints from its first nested block.
   322  
   323  ```hcl
   324  default {
   325    attr {
   326      name = "private"
   327      type = bool
   328    }
   329    literal {
   330      value = false
   331    }
   332  }
   333  ```
   334  
   335  A `default` spec block must have at least one nested spec block, and should
   336  generally have at least two since otherwise the `default` wrapper is a no-op.
   337  
   338  The second and any subsequent spec blocks are _fallback_ specs. These exhibit
   339  their usual behavior but are not able to impose validation constraints on the
   340  current body since they are not evaluated unless all prior specs produce
   341  `null` as their result.
   342  
   343  ## `transform` spec blocks
   344  
   345  The `transform` spec type evaluates one nested spec and then evaluates a given
   346  expression with that nested spec result to produce a final value.
   347  It creates no validation constraints of its own, but passes on the validation
   348  constraints from its nested block.
   349  
   350  ```hcl
   351  transform {
   352    attr {
   353      name = "size_in_mb"
   354      type = number
   355    }
   356  
   357    # Convert result to a size in bytes
   358    result = nested * 1024 * 1024
   359  }
   360  ```
   361  
   362  `transform` spec blocks accept the following argument:
   363  
   364  * `result` (required) - The expression to evaluate on the result of the nested
   365    spec. The variable `nested` is defined when evaluating this expression, with
   366    the result value of the nested spec.
   367  
   368  The `result` expression may use [functions](#spec-definition-functions).
   369  
   370  ## Predefined Variables
   371  
   372  `hcldec` accepts values for variables to expose into the input file's
   373  expression scope as CLI options, and this is the most common way to pass
   374  values since it allows them to be dynamically populated by the calling
   375  application.
   376  
   377  However, it's also possible to pre-define variables with constant values
   378  within a spec file, using the top-level `variables` block type:
   379  
   380  ```hcl
   381  variables {
   382    name = "Stephen"
   383  }
   384  ```
   385  
   386  Variables of the same name defined via the `hcldec` command line with override
   387  predefined variables of the same name, so this mechanism can also be used to
   388  provide defaults for variables that are overridden only in certain contexts.
   389  
   390  ## Custom Functions
   391  
   392  The spec can make arbitrary HCL functions available in the input file's
   393  expression scope, and thus allow simple computation within the input file,
   394  in addition to HCL's built-in operators.
   395  
   396  Custom functions are defined in the spec file with the top-level `function`
   397  block type:
   398  
   399  ```
   400  function "add_one" {
   401    params = [n]
   402    result = n + 1
   403  }
   404  ```
   405  
   406  Functions behave in a similar way to the `transform` spec type in that the
   407  given `result` attribute expression is evaluated with additional variables
   408  defined with the same names as the defined `params`.
   409  
   410  The [spec definition functions](#spec-definition-functions) can be used within
   411  custom function expressions, allowing them to be optionally exposed into the
   412  input file:
   413  
   414  ```
   415  function "upper" {
   416    params = [str]
   417    result = upper(str)
   418  }
   419  
   420  function "min" {
   421    params         = []
   422    variadic_param = nums
   423    result         = min(nums...)
   424  }
   425  ```
   426  
   427  Custom functions defined in the spec cannot be called from the spec itself.
   428  
   429  ## Spec Definition Functions
   430  
   431  Certain expressions within a specification may use the following functions.
   432  The documentation for each spec type above specifies where functions may
   433  be used.
   434  
   435  * `abs(number)` returns the absolute (positive) value of the given number.
   436  * `coalesce(vals...)` returns the first non-null value given.
   437  * `concat(lists...)` concatenates together all of the given lists to produce a new list.
   438  * `hasindex(val, idx)` returns true if the expression `val[idx]` could succeed.
   439  * `int(number)` returns the integer portion of the given number, rounding towards zero.
   440  * `jsondecode(str)` interprets the given string as JSON and returns the resulting data structure.
   441  * `jsonencode(val)` returns a JSON-serialized version of the given value.
   442  * `length(collection)` returns the number of elements in the given collection (list, set, map, object, or tuple).
   443  * `lower(string)` returns the given string with all uppercase letters converted to lowercase.
   444  * `max(numbers...)` returns the greatest of the given numbers.
   445  * `min(numbers...)` returns the smallest of the given numbers.
   446  * `reverse(string)` returns the given string with all of the characters in reverse order.
   447  * `strlen(string)` returns the number of characters in the given string.
   448  * `substr(string, offset, length)` returns the requested substring of the given string.
   449  * `upper(string)` returns the given string with all lowercase letters converted to uppercase.
   450  
   451  Note that these expressions are valid in the context of the _spec_ file, not
   452  the _input_. Functions can be exposed into the input file using
   453  [Custom Functions](#custom-functions) within the spec, which may in turn
   454  refer to these spec definition functions.
   455  
   456  ## Type Expressions
   457  
   458  Type expressions are used to describe the expected type of an attribute, as
   459  an additional validation constraint.
   460  
   461  A type expression uses primitive type names and compound type constructors.
   462  A type constructor builds a new type based on one or more type expression
   463  arguments.
   464  
   465  The following type names and type constructors are supported:
   466  
   467  * `any` is a wildcard that accepts a value of any type. (In HCL terms, this
   468    is the _dynamic pseudo-type_.)
   469  * `string` is a Unicode string.
   470  * `number` is an arbitrary-precision floating point number.
   471  * `bool` is a boolean value (`true` or `false`)
   472  * `list(element_type)` constructs a list type with the given element type
   473  * `set(element_type)` constructs a set type with the given element type
   474  * `map(element_type)` constructs a map type with the given element type
   475  * `object({name1 = element_type, name2 = element_type, ...})` constructs
   476    an object type with the given attribute types.
   477  * `tuple([element_type, element_type, ...])` constructs a tuple type with
   478    the given element types. This can be used, for example, to require an
   479    array with a particular number of elements, or with elements of different
   480    types.
   481  
   482  The above types are as defined by
   483  [the HCL syntax-agnostic information model](../../spec.md). After
   484  validation, values are lowered to JSON's type system, which is a subset
   485  of the HCL type system.
   486  
   487  `null` is a valid value of any type, and not a type itself.