PageSourceSearch

https://ethanhann.com/confval/assets/js/c4232e44.a557d026.js

js ethanhann.com collected 2026-10-04 19:33:03 UTC 15,956 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([["621"],{20837(e,n,t){t.r(n),t.d(n,{metadata:()=>r,default:()=>h,frontMatter:()=>a,contentTitle:()=>d,toc:()=>o,assets:()=>l});var r=JSON.parse('{"id":"guide/format-limitations","title":"Format Limitations","description":"When you parse a configuration in one format and emit it in another, or when you generate a template and wonder whether the write can fail, this page lists the gaps.","source":"@site/versioned_docs/version-0.10.0/guide/format-limitations.md","sourceDirName":"guide","slug":"/guide/format-limitations","permalink":"/confval/docs/0.10.0/guide/format-limitations","draft":false,"unlisted":false,"editUrl":"https://github.com/ethanhann/confval/tree/main/docs/versioned_docs/version-0.10.0/guide/format-limitations.md","tags":[],"version":"0.10.0","sidebarPosition":9,"frontMatter":{"sidebar_position":9},"sidebar":"tutorialSidebar","previous":{"title":"Representations","permalink":"/confval/docs/0.10.0/guide/representations"},"next":{"title":"Schema IR","permalink":"/confval/docs/0.10.0/guide/schema-ir"}}'),s=t(74848),i=t(28453);let a={sidebar_position:9},d="Format Limitations",l={},o=[{value:"Values outside the model",id:"values-outside-the-model",level:2},{value:"Values a format cannot write",id:"values-a-format-cannot-write",level:2},{value:"Names and repetition",id:"names-and-repetition",level:2},{value:"What template generation can rely on",id:"what-template-generation-can-rely-on",level:2},{value:"What is dropped by design",id:"what-is-dropped-by-design",level:2}];function c(e){let n={code:"code",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"format-limitations",children:"Format Limitations"})}),"\n",(0,s.jsx)(n.p,{children:"When you parse a configuration in one format and emit it in another, or when you generate a template and wonder whether the write can fail, this page lists the gaps.\nThe formats do not share one vocabulary.\nTOML has a datetime literal and JSON does not.\nKDL, TOML, and YAML write infinity where JSON and HCL have no token for it."}),"\n",(0,s.jsx)(n.p,{children:"A value that cannot be expressed produces an error naming the value and its dotted path.\nThis holds in every format.\nNothing is rounded, approximated, or dropped."}),"\n",(0,s.jsx)(n.h2,{id:"values-outside-the-model",children:"Values outside the model"}),"\n",(0,s.jsxs)(n.p,{children:["Every frontend parses into the same neutral field model, and the model's scalars are strings, ",(0,s.jsx)(n.code,{children:"i64"})," integers, ",(0,s.jsx)(n.code,{children:"f64"})," floats, and booleans.\nA source value outside that set still parses, but it is held as an opaque marker with a label rather than a value."]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Format"}),(0,s.jsx)(n.th,{children:"Source value"}),(0,s.jsx)(n.th,{children:"Label"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"TOML"}),(0,s.jsx)(n.td,{children:"a datetime"}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"datetime"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"TOML"}),(0,s.jsx)(n.td,{children:"a value with no neutral scalar"}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"value"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"HCL"}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"null"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"null"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"HCL"}),(0,s.jsx)(n.td,{children:"a string template or heredoc"}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"string template"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"HCL"}),(0,s.jsxs)(n.td,{children:["a number with no ",(0,s.jsx)(n.code,{children:"i64"})," or ",(0,s.jsx)(n.code,{children:"f64"})," value"]}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"number"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"HCL"}),(0,s.jsx)(n.td,{children:"any other expression, such as a function call or a variable"}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"expression"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"KDL"}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"#null"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"null"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"KDL"}),(0,s.jsxs)(n.td,{children:["an integer beyond ",(0,s.jsx)(n.code,{children:"i64"})]}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"oversized integer"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"JSON"}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"null"})}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"null"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"JSON"}),(0,s.jsxs)(n.td,{children:["an integer beyond ",(0,s.jsx)(n.code,{children:"i64"})]}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"oversized integer"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"JSON"}),(0,s.jsxs)(n.td,{children:["a number whose ",(0,s.jsx)(n.code,{children:"f64"})," value is not finite"]}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"oversized number"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"YAML"}),(0,s.jsxs)(n.td,{children:[(0,s.jsx)(n.code,{children:"null"}),", ",(0,s.jsx)(n.code,{children:"~"}),", or a key with no value"]}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"null"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"YAML"}),(0,s.jsxs)(n.td,{children:["an integer beyond ",(0,s.jsx)(n.code,{children:"i64"})]}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"oversized integer"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"YAML"}),(0,s.jsxs)(n.td,{children:["a decimal float that overflows ",(0,s.jsx)(n.code,{children:"f64"})]}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"oversized number"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"YAML"}),(0,s.jsxs)(n.td,{children:["an alias, ",(0,s.jsx)(n.code,{children:"*name"})]}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"alias"})})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"YAML"}),(0,s.jsx)(n.td,{children:"a tag the frontend refuses"}),(0,s.jsx)(n.td,{children:(0,s.jsx)(n.code,{children:"tagged value"})})]})]})]}),"\n",(0,s.jsxs)(n.p,{children:["A marker is not an error by itself.\nIt surfaces as an ordinary type mismatch when a spec field reads it.\nFor example, ",(0,s.jsx)(n.code,{children:'"when": null'})," under a string field reports ",(0,s.jsx)(n.code,{children:"expected string, found null"})," at the value.\nIt also refuses to emit to every format, because there is nothing faithful to write."]}),"\n",(0,s.jsx)(n.h2,{id:"values-a-format-cannot-write",children:"Values a format cannot write"}),"\n",(0,s.jsxs)(n.p,{children:["The model can hold a value that a target format has no literal for.\nEmitting one returns an ",(0,s.jsx)(n.code,{children:"EmitError"}
1)," rather than inventing a syntax for it."]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Target"}),(0,s.jsx)(n.th,{children:"Cannot write"}),(0,s.jsx)(n.th,{children:"Writes without trouble"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"TOML"}),(0,s.jsx)(n.td,{children:"nothing beyond the markers above"}),(0,s.jsxs)(n.td,{children:["non-finite floats, ",(0,s.jsx)(n.code,{children:"i64::MIN"}),", nested arrays, any key"]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"HCL"}),(0,s.jsx)(n.td,{children:"a non-finite float"}),(0,s.jsxs)(n.td,{children:[(0,s.jsx)(n.code,{children:"i64::MIN"}),", nested arrays, mixed arrays"]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"KDL"}),(0,s.jsx)(n.td,{children:"an array inside an array, an array mixing scalars and objects, an object inside a grouped repetition"}),(0,s.jsxs)(n.td,{children:["non-finite floats, as ",(0,s.jsx)(n.code,{children:"#inf"}),", ",(0,s.jsx)(n.code,{children:"#-inf"}),", and ",(0,s.jsx)(n.code,{children:"#nan"})]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"JSON"}),(0,s.jsx)(n.td,{children:"a non-finite float"}),(0,s.jsxs)(n.td,{children:["everything else, ",(0,s.jsx)(n.code,{children:"i64::MIN"})," included"]})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"YAML"}),(0,s.jsx)(n.td,{children:"nothing beyond the markers above"}),(0,s.jsxs)(n.td,{children:["non-finite floats, as ",(0,s.jsx)(n.code,{children:".inf"}),", ",(0,s.jsx)(n.code,{children:"-.inf"}),", and ",(0,s.jsx)(n.code,{children:".nan"}),", nested sequences, any key"]})]})]})]}),"\n",(0,s.jsx)(n.p,{children:"KDL's gaps all follow from one rule.\nA KDL argument must be a scalar, and the language has no inline array literal.\nThere is no way to write an inner array or an object inside a grouped repetition."}),"\n",(0,s.jsxs)(n.p,{children:["YAML has no gap in this table, and it carries two markers no other format produces.\nAn alias is not expanded, and a tag outside the core schema has no reading.\nA decimal that overflows ",(0,s.jsx)(n.code,{children:"f64"})," refuses rather than becoming an infinity the operator never wrote.\nJSON refuses the same value for the same reason."]}),"\n",(0,s.jsxs)(n.p,{children:["For example, a KDL config with ",(0,s.jsx)(n.code,{children:"rate #inf"})," converts to TOML, where it emits as ",(0,s.jsx)(n.code,{children:"inf"}),".\nConverting the same config to JSON returns an error at ",(0,s.jsx)(n.code,{children:"rate"}),", because JSON's grammar has no token for infinity."]}),"\n",(0,s.jsxs)(n.p,{children:["Block labels follow the same rule.\nHCL and KDL write a parsed block's native label back as label syntax.\n",(0,s.jsx)(n.code,{children:'upstream "api" { ... }'})," round-trips.\nTOML, JSON, and YAML have no label syntax.\nA parsed tree does not name the schema field that holds the label.\nEmitting a natively labeled level into one of these formats returns an ",(0,s.jsx)(n.code,{children:"EmitError"})," rather than dropping the label.\nTo convert a labeled configuration into those formats, parse it through the spec and emit a spec walk such as ",(0,s.jsx)(n.code,{children:"to_fields"}),", which writes the label as its designated child field."]}),"\n",(0,s.jsx)(n.h2,{id:"names-and-repetition",children:"Names and repetition"}),"\n",(0,s.jsx)(n.p,{children:"A name can also be one the target cannot write."}),"\n",(0,s.jsxs)(n.p,{children:["HCL attribute and block names must be identifiers.\nTOML, KDL, JSON, and YAML quote any name.\nA field named ",(0,s.jsx)(n.code,{children:"not an ident"})," emits to all four and fails to HCL alone.\nThis is the only source of an ",(0,s.jsx)(n.code,{children:"UnrepresentableName"})," error."]}),"\n",(0,s.jsx)(n.p,{children:"Repetition is format-specific, because each format refuses the shapes it would otherwise collapse without notice."}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"TOML refuses a value beside a same-named block, two same-named values, and any repetition inside an inline table."}),"\n",(0,s.jsx)(n.li,{children:"HCL repeats blocks freely and writes a value next to a same-named block, but it refuses a duplicate attribute name and any repetition inside an object."}),"\n",(0,s.jsx)(n.li,{children:"JSON refuses a value beside a same-named block, because the only way to write it is a duplicate key, which most consumers collapse to one member. Repeated values and repeated blocks group into arrays instead."}),"\n",(0,s.jsx)(n.li,{children:"YAML refuses a value beside a same-named block, for the same reason JSON does. Repeated values and repeated blocks group into sequences instead."}),"\n",(0,s.jsx)(n.li,{children:"KDL writes every repetition but one. Repeated values group into one node's arguments, repeated blocks are the native list form, and a value beside a same-named block emits as two nodes. A grouped repetition holding an object cannot be written, because an argument must be a scalar."}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"These shapes cannot come from a populated spec.\nThey arise only when you emit a tree parsed from a format that permits them, or one you built by hand."}),"\n",(0,s.jsx)(n.h2,{id:"what-template-generation-can-rely-on",children:"What template generation can rely on"}),"\n",(0,s.jsxs)(n.p,{children:["A populated spec is the tree ",(0,s.jsx)(n.code,{children:"to_fields"})," or ",(0,s.jsx)(n.code,{children:"to_template"})," builds from your spec types and their defaults.\nIt stays inside the vocabulary the formats share.\nNames are Rust identifiers, values are ordinary scalars, and nothing repeats."]}),"\n",(0,s.jsxs)(n.table,{children:[(0,s.jsx)(n.thead,{children:(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.th,{children:"Target"}),(0,s.jsx)(n.th,{children:"A populated spec fails when"})]})}),(0,s.jsxs)(n.tbody,{children:[(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"TOML"}),(0,s.jsx)(n.td,{children:"never"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"KDL"}),(0,s.jsx)(n.td,{children:"never"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"YAML"}),(0,s.jsx)(n.td,{children:"never"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"JSON"}),(0,s.jsx)(n.td,{children:"a float default is infinity or NaN"})]}),(0,s.jsxs)(n.tr,{children:[(0,s.jsx)(n.td,{children:"HCL"}),(0,s.jsx)(n.td,{children:"a float default is infinity or NaN"})]})]})]}),"\n",(0,s.jsxs)(n.p,{children:["If your defaults are ordinary numbers, template generation cannot fail.\nYou can ",(0,s.jsx)(n.code,{children:"expect"})," on the emit call."]}),"\n",(0,s.jsx)(n.h2,{id:"what-is-dropped-by-design",children:"What is dropped by design"}),"\n",(0,s.jsx)(n.p,{children:"A few things are lost in conversion without an error, because they are presentation rather than configuration."}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Operator layout and comments. Emit writes canonical text, and a parsed file's formatting is never held in the model."}),"\n",(0,s.jsx)(n.li,{children:"Doc comments in JSON. The other formats render template annotations as comments. JSON has no comment syntax, so a JSON template equals the populated output."}),"\n",(0,s.jsxs)(n.li,{children:["Which of two nesting syntaxes the source used. A TOML ",(0,s.jsx)(n.code,{children:"[table]"})," and an inline table, an HCL block and an object attribute, or a YAML block mapping and a flow mapping all read as the same structure and emit in the target's canonical form."]}),"\n",(0,s.jsxs)(n.li,{children:["Separate duplicate keys. JSON, YAML, and KDL group repeated names into one list on emit. A list-shaped field reads the same list it would have. A single-value field trades its ",(0,s.jsx)(n.code,{children:"duplicate field"})," report for a type mismatch on reparse, because the grouped member is an array where a scalar is expected."]}),"\n",(0,s.jsx)(n.li,{children:"The type of a layered override. Text from an environment variable or a command line flag reaches the model unparsed, and every format writes it as a string. A typed reparse of the emitted file reads those leaves as strings."}),"\n"]})]})}function h(e={}){let{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}},28453(e,n,t){t.d(n,{R:()=>a,x:()=>d});var r=t(96540);let s={},i=r.createContext(s);function a(e){let n=r.useContext(i);return r.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function d(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),r.createElement(i.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.