]>
Commit | Line | Data |
---|---|---|
15c0b25d AP |
1 | # HCL JSON Syntax Specification |
2 | ||
3 | This is the specification for the JSON serialization for hcl. HCL is a system | |
4 | for defining configuration languages for applications. The HCL information | |
5 | model is designed to support multiple concrete syntaxes for configuration, | |
6 | and this JSON-based format complements [the native syntax](../hclsyntax/spec.md) | |
7 | by being easy to machine-generate, whereas the native syntax is oriented | |
107c1cdb | 8 | towards human authoring and maintenance |
15c0b25d AP |
9 | |
10 | This syntax is defined in terms of JSON as defined in | |
11 | [RFC7159](https://tools.ietf.org/html/rfc7159). As such it inherits the JSON | |
12 | grammar as-is, and merely defines a specific methodology for interpreting | |
13 | JSON constructs into HCL structural elements and expressions. | |
14 | ||
15 | This mapping is defined such that valid JSON-serialized HCL input can be | |
16 | _produced_ using standard JSON implementations in various programming languages. | |
17 | _Parsing_ such JSON has some additional constraints not beyond what is normally | |
18 | supported by JSON parsers, so a specialized parser may be required that | |
19 | is able to: | |
20 | ||
107c1cdb ND |
21 | - Preserve the relative ordering of properties defined in an object. |
22 | - Preserve multiple definitions of the same property name. | |
23 | - Preserve numeric values to the precision required by the number type | |
15c0b25d | 24 | in [the HCL syntax-agnostic information model](../spec.md). |
107c1cdb | 25 | - Retain source location information for parsed tokens/constructs in order |
15c0b25d AP |
26 | to produce good error messages. |
27 | ||
28 | ## Structural Elements | |
29 | ||
30 | [The HCL syntax-agnostic information model](../spec.md) defines a _body_ as an | |
31 | abstract container for attribute definitions and child blocks. A body is | |
32 | represented in JSON as either a single JSON object or a JSON array of objects. | |
33 | ||
34 | Body processing is in terms of JSON object properties, visited in the order | |
35 | they appear in the input. Where a body is represented by a single JSON object, | |
36 | the properties of that object are visited in order. Where a body is | |
37 | represented by a JSON array, each of its elements are visited in order and | |
38 | each element has its properties visited in order. If any element of the array | |
39 | is not a JSON object then the input is erroneous. | |
40 | ||
41 | When a body is being processed in the _dynamic attributes_ mode, the allowance | |
42 | of a JSON array in the previous paragraph does not apply and instead a single | |
43 | JSON object is always required. | |
44 | ||
45 | As defined in the language-agnostic model, body processing is in terms | |
46 | of a schema which provides context for interpreting the body's content. For | |
47 | JSON bodies, the schema is crucial to allow differentiation of attribute | |
48 | definitions and block definitions, both of which are represented via object | |
49 | properties. | |
50 | ||
51 | The special property name `"//"`, when used in an object representing a HCL | |
52 | body, is parsed and ignored. A property with this name can be used to | |
53 | include human-readable comments. (This special property name is _not_ | |
54 | processed in this way for any _other_ HCL constructs that are represented as | |
55 | JSON objects.) | |
56 | ||
57 | ### Attributes | |
58 | ||
59 | Where the given schema describes an attribute with a given name, the object | |
60 | property with the matching name — if present — serves as the attribute's | |
61 | definition. | |
62 | ||
63 | When a body is being processed in the _dynamic attributes_ mode, each object | |
64 | property serves as an attribute definition for the attribute whose name | |
65 | matches the property name. | |
66 | ||
67 | The value of an attribute definition property is interpreted as an _expression_, | |
68 | as described in a later section. | |
69 | ||
70 | Given a schema that calls for an attribute named "foo", a JSON object like | |
71 | the following provides a definition for that attribute: | |
72 | ||
73 | ```json | |
74 | { | |
75 | "foo": "bar baz" | |
76 | } | |
77 | ``` | |
78 | ||
79 | ### Blocks | |
80 | ||
81 | Where the given schema describes a block with a given type name, each object | |
82 | property with the matching name serves as a definition of zero or more blocks | |
83 | of that type. | |
84 | ||
85 | Processing of child blocks is in terms of nested JSON objects and arrays. | |
86 | If the schema defines one or more _labels_ for the block type, a nested JSON | |
87 | object or JSON array of objects is required for each labelling level. These | |
88 | are flattened to a single ordered sequence of object properties using the | |
89 | same algorithm as for body content as defined above. Each object property | |
90 | serves as a label value at the corresponding level. | |
91 | ||
92 | After any labelling levels, the next nested value is either a JSON object | |
93 | representing a single block body, or a JSON array of JSON objects that each | |
94 | represent a single block body. Use of an array accommodates the definition | |
95 | of multiple blocks that have identical type and labels. | |
96 | ||
97 | Given a schema that calls for a block type named "foo" with no labels, the | |
98 | following JSON objects are all valid definitions of zero or more blocks of this | |
99 | type: | |
100 | ||
101 | ```json | |
102 | { | |
103 | "foo": { | |
104 | "child_attr": "baz" | |
105 | } | |
106 | } | |
107 | ``` | |
108 | ||
109 | ```json | |
110 | { | |
111 | "foo": [ | |
112 | { | |
113 | "child_attr": "baz" | |
114 | }, | |
115 | { | |
116 | "child_attr": "boz" | |
117 | } | |
118 | ] | |
119 | } | |
120 | ``` | |
107c1cdb | 121 | |
15c0b25d AP |
122 | ```json |
123 | { | |
124 | "foo": [] | |
125 | } | |
126 | ``` | |
127 | ||
128 | The first of these defines a single child block of type "foo". The second | |
129 | defines _two_ such blocks. The final example shows a degenerate definition | |
130 | of zero blocks, though generators should prefer to omit the property entirely | |
131 | in this scenario. | |
132 | ||
133 | Given a schema that calls for a block type named "foo" with _two_ labels, the | |
134 | extra label levels must be represented as objects or arrays of objects as in | |
135 | the following examples: | |
136 | ||
137 | ```json | |
138 | { | |
139 | "foo": { | |
140 | "bar": { | |
141 | "baz": { | |
142 | "child_attr": "baz" | |
143 | }, | |
144 | "boz": { | |
145 | "child_attr": "baz" | |
146 | } | |
147 | }, | |
148 | "boz": { | |
149 | "baz": { | |
150 | "child_attr": "baz" | |
107c1cdb | 151 | } |
15c0b25d AP |
152 | } |
153 | } | |
154 | } | |
155 | ``` | |
156 | ||
157 | ```json | |
158 | { | |
159 | "foo": { | |
160 | "bar": { | |
161 | "baz": { | |
162 | "child_attr": "baz" | |
163 | }, | |
164 | "boz": { | |
165 | "child_attr": "baz" | |
166 | } | |
167 | }, | |
168 | "boz": { | |
169 | "baz": [ | |
170 | { | |
171 | "child_attr": "baz" | |
172 | }, | |
173 | { | |
174 | "child_attr": "boz" | |
175 | } | |
176 | ] | |
177 | } | |
178 | } | |
179 | } | |
180 | ``` | |
181 | ||
182 | ```json | |
183 | { | |
184 | "foo": [ | |
185 | { | |
186 | "bar": { | |
187 | "baz": { | |
188 | "child_attr": "baz" | |
189 | }, | |
190 | "boz": { | |
191 | "child_attr": "baz" | |
192 | } | |
107c1cdb | 193 | } |
15c0b25d AP |
194 | }, |
195 | { | |
196 | "bar": { | |
197 | "baz": [ | |
198 | { | |
199 | "child_attr": "baz" | |
200 | }, | |
201 | { | |
202 | "child_attr": "boz" | |
203 | } | |
204 | ] | |
205 | } | |
206 | } | |
207 | ] | |
208 | } | |
209 | ``` | |
210 | ||
211 | ```json | |
212 | { | |
213 | "foo": { | |
214 | "bar": { | |
215 | "baz": { | |
216 | "child_attr": "baz" | |
217 | }, | |
218 | "boz": { | |
219 | "child_attr": "baz" | |
220 | } | |
221 | }, | |
222 | "bar": { | |
223 | "baz": [ | |
224 | { | |
225 | "child_attr": "baz" | |
226 | }, | |
227 | { | |
228 | "child_attr": "boz" | |
229 | } | |
230 | ] | |
231 | } | |
232 | } | |
233 | } | |
234 | ``` | |
235 | ||
236 | Arrays can be introduced at either the label definition or block body | |
237 | definition levels to define multiple definitions of the same block type | |
238 | or labels while preserving order. | |
239 | ||
240 | A JSON HCL parser _must_ support duplicate definitions of the same property | |
241 | name within a single object, preserving all of them and the relative ordering | |
242 | between them. The array-based forms are also required so that JSON HCL | |
243 | configurations can be produced with JSON producing libraries that are not | |
244 | able to preserve property definition order and multiple definitions of | |
245 | the same property. | |
246 | ||
247 | ## Expressions | |
248 | ||
249 | JSON lacks a native expression syntax, so the HCL JSON syntax instead defines | |
250 | a mapping for each of the JSON value types, including a special mapping for | |
251 | strings that allows optional use of arbitrary expressions. | |
252 | ||
253 | ### Objects | |
254 | ||
255 | When interpreted as an expression, a JSON object represents a value of a HCL | |
256 | object type. | |
257 | ||
258 | Each property of the JSON object represents an attribute of the HCL object type. | |
259 | The property name string given in the JSON input is interpreted as a string | |
260 | expression as described below, and its result is converted to string as defined | |
261 | by the syntax-agnostic information model. If such a conversion is not possible, | |
262 | an error is produced and evaluation fails. | |
263 | ||
264 | An instance of the constructed object type is then created, whose values | |
265 | are interpreted by again recursively applying the mapping rules defined in | |
266 | this section to each of the property values. | |
267 | ||
268 | If any evaluated property name strings produce null values, an error is | |
269 | produced and evaluation fails. If any produce _unknown_ values, the _entire | |
270 | object's_ result is an unknown value of the dynamic pseudo-type, signalling | |
271 | that the type of the object cannot be determined. | |
272 | ||
273 | It is an error to define the same property name multiple times within a single | |
274 | JSON object interpreted as an expression. In full expression mode, this | |
275 | constraint applies to the name expression results after conversion to string, | |
276 | rather than the raw string that may contain interpolation expressions. | |
277 | ||
278 | ### Arrays | |
279 | ||
280 | When interpreted as an expression, a JSON array represents a value of a HCL | |
281 | tuple type. | |
282 | ||
283 | Each element of the JSON array represents an element of the HCL tuple type. | |
107c1cdb | 284 | The tuple type is constructed by enumerating the JSON array elements, creating |
15c0b25d | 285 | for each an element whose type is the result of recursively applying the |
107c1cdb | 286 | expression mapping rules. Correspondence is preserved between the array element |
15c0b25d AP |
287 | indices and the tuple element indices. |
288 | ||
289 | An instance of the constructed tuple type is then created, whose values are | |
290 | interpreted by again recursively applying the mapping rules defined in this | |
291 | section. | |
292 | ||
293 | ### Numbers | |
294 | ||
295 | When interpreted as an expression, a JSON number represents a HCL number value. | |
296 | ||
297 | HCL numbers are arbitrary-precision decimal values, so a JSON HCL parser must | |
298 | be able to translate exactly the value given to a number of corresponding | |
299 | precision, within the constraints set by the HCL syntax-agnostic information | |
300 | model. | |
301 | ||
302 | In practice, off-the-shelf JSON serializers often do not support customizing the | |
303 | processing of numbers, and instead force processing as 32-bit or 64-bit | |
304 | floating point values. | |
305 | ||
306 | A _producer_ of JSON HCL that uses such a serializer can provide numeric values | |
307 | as JSON strings where they have precision too great for representation in the | |
308 | serializer's chosen numeric type in situations where the result will be | |
309 | converted to number (using the standard conversion rules) by a calling | |
310 | application. | |
311 | ||
312 | Alternatively, for expressions that are evaluated in full expression mode an | |
313 | embedded template interpolation can be used to faithfully represent a number, | |
314 | such as `"${1e150}"`, which will then be evaluated by the underlying HCL native | |
315 | syntax expression evaluator. | |
316 | ||
317 | ### Boolean Values | |
318 | ||
319 | The JSON boolean values `true` and `false`, when interpreted as expressions, | |
320 | represent the corresponding HCL boolean values. | |
321 | ||
322 | ### The Null Value | |
323 | ||
324 | The JSON value `null`, when interpreted as an expression, represents a | |
325 | HCL null value of the dynamic pseudo-type. | |
326 | ||
327 | ### Strings | |
328 | ||
107c1cdb | 329 | When interpreted as an expression, a JSON string may be interpreted in one of |
15c0b25d AP |
330 | two ways depending on the evaluation mode. |
331 | ||
332 | If evaluating in literal-only mode (as defined by the syntax-agnostic | |
333 | information model) the literal string is intepreted directly as a HCL string | |
334 | value, by directly using the exact sequence of unicode characters represented. | |
335 | Template interpolations and directives MUST NOT be processed in this mode, | |
336 | allowing any characters that appear as introduction sequences to pass through | |
337 | literally: | |
338 | ||
339 | ```json | |
340 | "Hello world! Template sequences like ${ are not intepreted here." | |
341 | ``` | |
342 | ||
343 | When evaluating in full expression mode (again, as defined by the syntax- | |
344 | agnostic information model) the literal string is instead interpreted as a | |
345 | _standalone template_ in the HCL Native Syntax. The expression evaluation | |
346 | result is then the direct result of evaluating that template with the current | |
347 | variable scope and function table. | |
348 | ||
349 | ```json | |
350 | "Hello, ${name}! Template sequences are interpreted in full expression mode." | |
351 | ``` | |
352 | ||
353 | In particular the _Template Interpolation Unwrapping_ requirement from the | |
354 | HCL native syntax specification must be implemented, allowing the use of | |
355 | single-interpolation templates to represent expressions that would not | |
356 | otherwise be representable in JSON, such as the following example where | |
357 | the result must be a number, rather than a string representation of a number: | |
358 | ||
359 | ```json | |
360 | "${ a + b }" | |
361 | ``` | |
362 | ||
363 | ## Static Analysis | |
364 | ||
365 | The HCL static analysis operations are implemented for JSON values that | |
366 | represent expressions, as described in the following sections. | |
367 | ||
368 | Due to the limited expressive power of the JSON syntax alone, use of these | |
369 | static analyses functions rather than normal expression evaluation is used | |
370 | as additional context for how a JSON value is to be interpreted, which means | |
371 | that static analyses can result in a different interpretation of a given | |
372 | expression than normal evaluation. | |
373 | ||
374 | ### Static List | |
375 | ||
376 | An expression interpreted as a static list must be a JSON array. Each of the | |
377 | values in the array is interpreted as an expression and returned. | |
378 | ||
379 | ### Static Map | |
380 | ||
381 | An expression interpreted as a static map must be a JSON object. Each of the | |
382 | key/value pairs in the object is presented as a pair of expressions. Since | |
383 | object property names are always strings, evaluating the key expression with | |
384 | a non-`nil` evaluation context will evaluate any template sequences given | |
385 | in the property name. | |
386 | ||
387 | ### Static Call | |
388 | ||
389 | An expression interpreted as a static call must be a string. The content of | |
390 | the string is interpreted as a native syntax expression (not a _template_, | |
391 | unlike normal evaluation) and then the static call analysis is delegated to | |
392 | that expression. | |
393 | ||
394 | If the original expression is not a string or its contents cannot be parsed | |
395 | as a native syntax expression then static call analysis is not supported. | |
396 | ||
397 | ### Static Traversal | |
398 | ||
399 | An expression interpreted as a static traversal must be a string. The content | |
400 | of the string is interpreted as a native syntax expression (not a _template_, | |
401 | unlike normal evaluation) and then static traversal analysis is delegated | |
402 | to that expression. | |
403 | ||
404 | If the original expression is not a string or its contents cannot be parsed | |
405 | as a native syntax expression then static call analysis is not supported. |