Skip to content

@idfkit/core

The portable surface: parsing, writing, and the object model. Every export here is synchronous and takes strings, so the same code runs in Node, a browser, a worker, and an edge runtime. File and network access lives in @idfkit/core/node and SchemaBundle.

npm install @idfkit/core @idfkit/schemas
Classes

IdfCollection

Name-indexed collection of objects of one type.

Iterable, so for (const zone of doc.all('Zone')) works, and array-like enough that [...collection], .map, .filter read naturally. Lookup by name is O(1) and case-insensitive, matching EnergyPlus semantics.

Insertion order is preserved. IDF files are hand-edited and diffed, so reordering objects on a round-trip would produce noisy diffs for no reason.

Constructors

constructor

IdfCollection

Properties

typeName

Accessors

first

only

size

Methods

[iterator]


filter


find


get


Look up by name, case-insensitively.

has


map


names


require


Look up by name, throwing if absent.

toArray


where


Objects whose field equals value, compared case-insensitively.

IDFDocument

An EnergyPlus model.

Holds collections keyed by object type, a live reference graph, and the schema for one specific EnergyPlus version. Every document is bound to a version at construction; there is no version-agnostic mode, because field order and reference lists genuinely differ between releases.

The optional M parameter attaches a generated type map, which makes field access statically checked without changing anything at runtime. See typemap.ts.

Constructors

constructor

IDFDocument

Properties

schema

Accessors

references

size

version

Methods

add


Create an object and attach it to the document.

Anonymous types (Version, Timestep) take null for the name and get a synthetic key that never appears in output.

addRaw


Untyped object creation, for the parsers.

They work from runtime strings, so the compiler cannot check them against the type map. Same reasoning as collection(): one deliberate seam rather than casts scattered through the parse loop.

all


Every object of one type.

When the document carries a generated type map, the argument completes among that version's type names and the result is narrowed to the matching field interface. Unknown names still work and simply stay untyped, which is what version-generic code needs.

attach


Attach an existing detached object, e.g. one produced by clone().

Repeats the checks addRaw makes rather than trusting the object. An object carries its own schema definition, so one cloned out of a document on a different EnergyPlus version would otherwise be written using that version's field order under this document's Version header, which mis-maps every field on reload instead of failing.

collection


Untyped collection access.

The public all() is generic over the type map, which means the compiler cannot verify calls made from inside this class or from the parsers, where the type name is a runtime string. Those go through here instead, so the single unavoidable cast lives in one place rather than at every call site.

danglingReferences


Reference targets that no object provides.

get


One object by type and name.

has


Whether any object of this type exists.

objects


Every object in the document, grouped by type in insertion order.

onFieldChanged


onNameChanged


remove


Remove an object. Does not touch objects that referenced it.

rename


Rename an object and rewrite every reference to it.

Equivalent to assigning obj.name.

require


One object by type and name, throwing if absent.

toJSON


epJSON representation.

Anonymous objects get the "<type> 1" key EnergyPlus itself emits, which is what makes the output loadable by the real engine.

types


Object type names present in this document, in insertion order.

IdfObject

A single EnergyPlus object.

Field access is via real accessors installed on a per-type prototype, so zone.ceiling_height is an ordinary property read that TypeScript can see (given the generated interfaces) and V8 can inline. See shape.ts.

Field names are epJSON names (zone_name, outside_boundary_condition), not the space-separated IDD names. That is a deliberate break from the Python library's IDF-to-Python conversion: epJSON names are already valid JS identifiers and valid TS interface keys, so using them directly means the on-disk name, the runtime key, and the static type all agree.

Properties

[DATA]

[KEY]

[NAME]

[OWNER]

[SHAPE]

Accessors

extensible

fieldNames

isNamed

key

name

schema

typeName

Methods

clone


Detached deep copy, optionally renamed. Not attached to any document.

declaredNames


Names this object contributes to the model's reference lists.

Usually just name, but anonymous types like FluidProperties:Name carry their identity in an ordinary field instead, and other objects reference that value. Treating those as nameless makes every pointer at them look dangling.

fieldSchema


Schema definition for one field.

get


Read a field by name. Untyped escape hatch for version-generic code.

hasField


Whether the schema defines this field for this object type.

outgoingReferences


Names this object's fields point at, paired with the field holding them.

Extensible groups are included, with index naming the repeat the value sits in. Half the references in a real model live there.

set


Write a field by name, going through the same hooks as property access.

setFieldNames


Field names that are actually set on this object.

toJSON


Plain epJSON body: field values only, without the name.

toString


update


Apply several fields at once.

create


IdfParseError

Constructors

constructor

IdfParseError

Properties

line

typeName

ObjectShape

Per-object-type prototype carrying real accessors for every field.

The Python library resolves zone.ceiling_height through __getattr__. The mechanical translation of that is a Proxy, which we deliberately do not use: proxies defeat V8's inline caches, and more importantly they are invisible to TypeScript, so nothing would autocomplete. Instead each object type gets one prototype with Object.defineProperty accessors, built once and shared by every instance of that type. Property access is then an ordinary monomorphic lookup, and the generated .d.ts interfaces describe it statically.

Shapes are keyed by the schema definition object rather than by type name. Because the schema bundle is content-addressed, Zone in 9.4.0 and Zone in 26.1.0 are the same frozen definition, so they share one shape and one prototype. Cross-version documents stay monomorphic for free.

Constructors

constructor

ObjectShape

Properties

extensibleKey

Extensible array key (vertices), if this type has one.

extensibleRefFields

Fields inside the extensible group that point into a reference list.

Kept separate from refFields because these live in type.x.fields, not the positional field list, and so need the repeat index to address them. Ignoring them is not cosmetic: ZoneList, Branch, and the supply/return paths carry all of their references here, so leaving them out of the graph makes rename() silently produce a broken model.

fields

Field names in IDF positional order, excluding the name field.

keyFields

Fields whose value declares a name other objects may reference.

named

Whether the object carries a name (most do; Version does not).

proto

refFields

Fields that point into a reference list, i.e. foreign keys.

type

typeName

ReferenceGraph

Live index of every name-to-name reference in a document.

Kept current by the document as objects are added, removed, renamed, and edited, so referencing() is a lookup rather than a scan. EnergyPlus models are dense with references (every surface names a zone and a construction, every construction names materials), and the rename-propagation behaviour that makes the library useful depends on this being exact.

Names are matched case-insensitively, because EnergyPlus resolves them that way, but the original casing is preserved for round-tripping.

Constructors

constructor

ReferenceGraph

Accessors

size

Methods

add


Record that obj.field points at target.

addObject


Index every reference field of an object at once.

clear


dangling


Edges whose target does not exist. valid holds lowercased names.

isReferenced


Whether anything points at this name.

referencedBy


Names an object points at.

referencing


Edges pointing at a name.

referencingObjects


Objects that reference a name, deduplicated.

removeObject


Drop every edge originating from an object.

retarget


Rewrite every edge pointing at previous to point at next.

Only updates the index. The document is responsible for writing the new value into the referencing objects' fields, which it does without going back through the setter hook to avoid re-entering this method.

updateField


Update the edge for a single field after its value changed.

Schema

A single EnergyPlus version's schema, backed by a shared blob store.

Type definitions are hydrated lazily and cached in the store, so loading a second version only pays for the definitions that version does not already share with one in memory. In practice that is a couple hundred out of 858.

Constructors

constructor

Schema

Properties

version

Accessors

typeNames

Methods

changedFrom


Object type names whose definition hash differs from other.

Because definitions are content-addressed this is a manifest comparison, not a deep diff of two 10 MB documents, which is what makes cross-version work (migration planning, "what changed in 25.2") cheap.

field


Field definition for a type, or undefined.

get


Definition for an object type, or undefined if this version lacks it.

has


Whether this version defines the given object type. Case-insensitive.

require


Definition for an object type, throwing if absent.

resolve


Resolve a possibly mis-cased type name to its canonical spelling.

IDF is case-insensitive on type names and real files are inconsistent (ZONE, Zone, zone all appear in the wild), so every lookup path goes through here rather than trusting the input.

SchemaBundle

Loads schemas from a bundle, sharing one blob store across every version.

Hold one of these for the lifetime of the process. Loading 26.1.0 and then 9.4.0 costs far less than twice one version, because most definitions are byte-identical and already hydrated.

Constructors

constructor

SchemaBundle

Methods

latest


The newest version in the bundle.

load


Load one version's schema.

Repeat calls return the same instance; concurrent calls share one fetch.

loaded


A version already loaded, or undefined. Synchronous by design.

versions


Versions this bundle can serve, oldest first.

Interfaces

BundleSource

Where bundle files come from.

The only runtime-specific part of this package. Node reads from disk, the browser fetches over HTTP, and a bundler-driven app can supply its own resolver backed by import(). Everything above this interface is portable.

Methods

read


LexDiagnostic

Properties

line

message

LexOptions

Properties

onDiagnostic

Report a problem instead of throwing.

ObjectOwner

Something that wants to know when an object changes.

Implemented by IDFDocument. Declared as an interface so a detached object has no dependency on the document at all.

Methods

onFieldChanged


onNameChanged


ObjectWriteOptions

Properties

commentColumn

comments

indent

ParseDiagnostic

Properties

line

message

typeName

Object type the problem occurred in, when known.

ParseOptions

Properties

onDiagnostic

Collects diagnostics when strict is false.

strict

Throw on the first diagnostic instead of collecting them.

ParseResult

Properties

diagnostics

document

RawObject

A raw object as it appears in the file, before schema interpretation.

Properties

line

1-based line where the object starts, for diagnostics.

typeName

Type name exactly as written, e.g. BuildingSurface:Detailed.

values

Comma-separated values after the type name, trimmed, comments stripped.

ReferenceEdge

One field of one object pointing at a name.

Properties

field

from

index

Repeat index, when the field lives inside an extensible group. Absent for ordinary positional fields, which is what distinguishes the two.

target

SchemaDelta

Properties

added

Types present in this version but not the other.

changed

Types present in both, with a differing definition.

removed

Types present in the other version but not this one.

SlimField

Properties

auto

Field accepts Autosize / Autocalculate in addition to a number.

d

Schema default, applied on write when the field is absent.

e

Permitted values for a choice field.

max

min

ol

Names of reference lists this field points into (i.e. it is a foreign key).

rc

Value is case-sensitive and must not be normalized.

ref

Names of reference lists this field contributes to (i.e. it is a key).

t

Storage class.

u

SI units, used by the unit-conversion helpers.

xmax

Exclusive maximum.

xmin

Exclusive minimum.

SlimType

Properties

anon

Object has no name field at all, e.g. Version, GlobalGeometryRules.

f

All field names in IDF positional order, from legacy_idd.fields.

g

IDD group, e.g. Thermal Zones and Surfaces.

nref

Reference lists the object's name contributes to.

nreq

Object's name is required.

p

Field definitions, keyed by epJSON field name.

r

Required field names.

s

Object is a singleton (maxProperties: 1), e.g. Version, Building.

x

Extensible group definition, if the object has one.

WriteEpJsonOptions

Properties

indent

Indent width. 0 emits compact JSON.

WriteIdfOptions

Properties

commentColumn

Column the field-name comments are aligned to.

comments

Emit !- Field Name comments after each field.

indent

Indent for field lines.

versionFirst

Write Version first regardless of insertion order. EnergyPlus does not require it, but every tool in the ecosystem expects it and diffs are cleaner when it is stable.

Type Aliases

AnyTypeMap

Base constraint: any map from object type name to its field interface.

EpJson

epJSON document shape: type -> name -> field values.

ExtensibleGroup

One repeat of an extensible group, e.g. a single vertex.

FieldValue

A scalar field value. undefined means the field is absent.

FieldValues

Field values accepted when constructing or updating an object.

ObjectOf

Field interface for a type name, or an empty object for unknown names.

StoredValue

Anything storable in a field slot.

TypeNameOf

Accepted type names for a map.

The string & {} arm is what keeps literal completion alive while still accepting arbitrary strings: without it TypeScript widens the parameter to string and the suggestions disappear.

UntypedMap

A document with no version types attached.

ValuesOf

Field values accepted when creating an object of a given type.

Deliberately not ObjectOf. For a known type name this is the exact field interface, so TypeScript's excess-property check rejects a misspelled field in an object literal. For anything else it widens to the permissive FieldValues, which is what version-generic code and untyped documents need. Using one type for both would force a choice between catching typos and allowing dynamic field names; using two costs nothing and gives both.

Functions

compareVersions

detectEpJsonVersion

detectVersion

httpSource

lex

parseEpJson

parseIdf

resolveVersion

shapeFor

shapeOf

toEpJson

versionKey

writeEpJson

writeIdf

writeObject