Slim schema format¶
@idfkit/schemas does not ship the raw epJSON schemas. It ships a reduced form
carrying everything needed to parse, write, and resolve references, with the
documentation metadata removed. This page describes that form; see
Content-addressed schemas for why
it exists. The format is specific to the TypeScript packages: Python reads the
epJSON schemas EnergyPlus publishes, one gzipped file per release, and has no
slim form.
Keys are single letters. This file is parsed on every cold start, and in a browser that start is a page load.
Bundle layout¶
data/
index.json.gz versions, and the manifest file for each
types.json.gz every unique type definition, keyed by content hash
manifest-26-1-0.json.gz type name -> hash, for one version
manifest-25-2-0.json.gz
...
index.json is BundleIndex: a versions array, oldest first, and a
manifests record mapping version string to manifest file name. A manifest is a
flat Record<typeName, hash>. types.json is a flat Record<hash, SlimType>,
shared by every version.
Files are gzipped and inflated by the source. httpSource uses
DecompressionStream so the payload stays around 1 MB. It sniffs the gzip magic
bytes first, so it works whether the server leaves Content-Encoding unset or
sets it for the .gz extension, where the client inflates the body itself.
SlimType¶
One object type, e.g. Zone.
| Key | Meaning |
|---|---|
f |
All field names in IDF positional order, from legacy_idd.fields |
p |
Field definitions, keyed by epJSON field name |
r |
Required field names |
nref |
Reference lists the object's name contributes to |
nreq |
1 when the name is required |
s |
1 when the object is a singleton, e.g. Version, Building |
anon |
1 when the object has no name field at all, e.g. GlobalGeometryRules |
x |
Extensible group definition, if the type has one |
g |
IDD group, e.g. Thermal Zones and Surfaces |
f is the load-bearing one: IDF is positional, and this array is the only thing
that says which slot a value belongs to.
SlimField¶
| Key | Meaning |
|---|---|
t |
Storage class, see below |
auto |
1 when the field is an anyOf of a numeric branch and a string branch |
se |
String literals that anyOf string branch accepts, see below |
ol |
Reference lists this field points into: it is a foreign key |
ref |
Reference lists this field contributes to: it is a key |
e |
Permitted values, for a choice field. Numbers on the fields that state choices numerically |
d |
Schema default, applied on write when the field is absent |
min |
Inclusive minimum |
max |
Inclusive maximum |
xmin |
Exclusive minimum, or true on a draft-04 version, see below |
xmax |
Exclusive maximum, or true on a draft-04 version, see below |
u |
SI units, e.g. m |
rc |
1 when the value is case-sensitive and must not be normalized |
ol and ref together are what the reference
graph is built from: ref says a name enters a list,
ol says a field reads from one.
auto and se, the two branches of an anyOf¶
13060 fields across the 17 bundled versions are declared anyOf: [{number},
{string}]: a capacity is a number, or the word that asks EnergyPlus to size it.
The bundle hoists the numeric branch onto the record, so t, e, min, max,
xmin and xmax all describe that branch, and sets auto. What survives of the
string branch is se, its enum, verbatim.
se is absent when the string branch declared no enum, and any string is legal
there. 646 fields have that shape, Schedule:Compact's extensible field among
them. That is why the empty string is kept in se rather than filtered out the
way it is filtered out of e: se: [""] and no se at all are opposite claims.
Nothing about the sentinel can be assumed. 10565 fields take Autosize and 1781
take Autocalculate, and a consumer that accepts either everywhere accepts a
value EnergyPlus rejects.
xmin and xmax, in two JSON Schema dialects¶
From 9.6.0 the schemas are draft-06 or later, where exclusiveMinimum carries
the bound itself, and xmin is a number. For 8.9.0 through 9.5.0 they are
draft-04, where the keyword is a boolean qualifying the sibling minimum, and
xmin is true. No version mixes the two. Branch on the type of the value, not
on the version: comparing a value against true silently compares it against 1.
FieldKind¶
The t key. It records how a value must be formatted on the way back out, which
JavaScript cannot recover on its own: 3 and 3.0 are the same number at
runtime.
| Value | Meaning |
|---|---|
'a' |
Alpha. Written verbatim. |
'n' |
Real. Written with a decimal point preserved. |
'i' |
Integer. Written without a decimal point. |
'arr' |
Extensible array wrapper. |
SlimExtensible¶
The x key on a type that has repeating field groups.
| Key | Meaning |
|---|---|
key |
epJSON key holding the array, e.g. vertices |
fields |
Field names inside each repeat group, in IDF order |
p |
Definitions for the inner fields, from the array's items |
What is dropped¶
note, memo, ip-units, and field_info. That is documentation metadata,
it is most of the weight, and it sits on the critical path of every parse.
Tooling that renders EnergyPlus documentation should read the source schemas
directly, or use idfkit-docs.
Reading a definition¶
import { localBundle } from '@idfkit/schemas/node';
const schema = await localBundle().load('26.1.0');
schema.resolve('ZONE'); // 'Zone'. IDF type names are case-insensitive
schema.get('Zone'); // the SlimType
schema.field('Zone', 'x_origin'); // { t: 'n', u: 'm', d: 0 }
Definitions are frozen and shared by identity across versions with the same content hash, so they must not be mutated.