@idfkit/core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +120 -0
  3. package/dist/collection.d.ts +48 -0
  4. package/dist/collection.d.ts.map +1 -0
  5. package/dist/collection.js +100 -0
  6. package/dist/collection.js.map +1 -0
  7. package/dist/document.d.ts +100 -0
  8. package/dist/document.d.ts.map +1 -0
  9. package/dist/document.js +0 -0
  10. package/dist/document.js.map +1 -0
  11. package/dist/index.d.ts +30 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +21 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/internal.d.ts +25 -0
  16. package/dist/internal.d.ts.map +1 -0
  17. package/dist/internal.js +25 -0
  18. package/dist/internal.js.map +1 -0
  19. package/dist/node.d.ts +40 -0
  20. package/dist/node.d.ts.map +1 -0
  21. package/dist/node.js +70 -0
  22. package/dist/node.js.map +1 -0
  23. package/dist/object.d.ts +114 -0
  24. package/dist/object.d.ts.map +1 -0
  25. package/dist/object.js +224 -0
  26. package/dist/object.js.map +1 -0
  27. package/dist/parse/epjson.d.ts +16 -0
  28. package/dist/parse/epjson.d.ts.map +1 -0
  29. package/dist/parse/epjson.js +91 -0
  30. package/dist/parse/epjson.js.map +1 -0
  31. package/dist/parse/idf.d.ts +44 -0
  32. package/dist/parse/idf.d.ts.map +1 -0
  33. package/dist/parse/idf.js +170 -0
  34. package/dist/parse/idf.js.map +1 -0
  35. package/dist/parse/lexer.d.ts +37 -0
  36. package/dist/parse/lexer.d.ts.map +1 -0
  37. package/dist/parse/lexer.js +105 -0
  38. package/dist/parse/lexer.js.map +1 -0
  39. package/dist/references.d.ts +56 -0
  40. package/dist/references.d.ts.map +1 -0
  41. package/dist/references.js +147 -0
  42. package/dist/references.js.map +1 -0
  43. package/dist/shape.d.ts +54 -0
  44. package/dist/shape.d.ts.map +1 -0
  45. package/dist/shape.js +114 -0
  46. package/dist/shape.js.map +1 -0
  47. package/dist/typemap.d.ts +43 -0
  48. package/dist/typemap.d.ts.map +1 -0
  49. package/dist/typemap.js +18 -0
  50. package/dist/typemap.js.map +1 -0
  51. package/dist/types/v26-1.d.ts +65896 -0
  52. package/dist/types/v26-1.d.ts.map +1 -0
  53. package/dist/types/v26-1.js +5 -0
  54. package/dist/types/v26-1.js.map +1 -0
  55. package/dist/types/v9-4.d.ts +61414 -0
  56. package/dist/types/v9-4.d.ts.map +1 -0
  57. package/dist/types/v9-4.js +5 -0
  58. package/dist/types/v9-4.js.map +1 -0
  59. package/dist/versions.d.ts +17 -0
  60. package/dist/versions.d.ts.map +1 -0
  61. package/dist/versions.js +34 -0
  62. package/dist/versions.js.map +1 -0
  63. package/dist/write/epjson.d.ts +15 -0
  64. package/dist/write/epjson.d.ts.map +1 -0
  65. package/dist/write/epjson.js +10 -0
  66. package/dist/write/epjson.js.map +1 -0
  67. package/dist/write/idf.d.ts +47 -0
  68. package/dist/write/idf.d.ts.map +1 -0
  69. package/dist/write/idf.js +149 -0
  70. package/dist/write/idf.js.map +1 -0
  71. package/package.json +55 -0
package/dist/node.js ADDED
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Node-only conveniences.
3
+ *
4
+ * This is the async edge of the library. The core is sync and pure; everything
5
+ * that touches a disk or a network is here, so the portable surface never has
6
+ * to be async "just in case" and browser bundles never pull in `node:fs`.
7
+ */
8
+ import { readFile, writeFile } from 'node:fs/promises';
9
+ import { SchemaBundle } from '@idfkit/schemas';
10
+ import { localBundle } from '@idfkit/schemas/node';
11
+ import { detectEpJsonVersion, parseEpJson } from './parse/epjson.js';
12
+ import { detectVersion, parseIdf } from './parse/idf.js';
13
+ import { resolveVersion } from './versions.js';
14
+ import { writeEpJson } from './write/epjson.js';
15
+ import { writeIdf } from './write/idf.js';
16
+ let defaultBundle;
17
+ /** The schema bundle shipped with `@idfkit/schemas`, created once per process. */
18
+ export function schemas() {
19
+ defaultBundle ??= localBundle();
20
+ return defaultBundle;
21
+ }
22
+ /**
23
+ * Resolve the schema for a file whose version was detected from its contents.
24
+ *
25
+ * Exported because callers who parse text themselves still need this step, and
26
+ * getting it wrong (loading 26.1 for a 9.0 file) silently mis-maps every
27
+ * positional field rather than failing loudly.
28
+ */
29
+ export async function schemaFor(detected, options = {}) {
30
+ const bundle = options.bundle ?? schemas();
31
+ if (options.version !== undefined)
32
+ return bundle.load(options.version);
33
+ if (detected === undefined) {
34
+ throw new Error('No Version object found. Pass `version` explicitly to parse a versionless file.');
35
+ }
36
+ const available = await bundle.versions();
37
+ const resolved = resolveVersion(detected, available);
38
+ if (resolved === undefined) {
39
+ throw new Error(`EnergyPlus ${detected} is not supported. Available: ${available.join(', ')}`);
40
+ }
41
+ return bundle.load(resolved);
42
+ }
43
+ /** Read and parse an IDF file. */
44
+ export async function loadIdf(path, options = {}) {
45
+ return (await loadIdfWithDiagnostics(path, options)).document;
46
+ }
47
+ /** Read and parse an IDF file, keeping non-fatal diagnostics. */
48
+ export async function loadIdfWithDiagnostics(path, options = {}) {
49
+ // latin-1 rather than utf-8: EnergyPlus example files and vendor-exported
50
+ // models routinely contain single high bytes (degree signs, accented station
51
+ // names) that are not valid utf-8 and would otherwise decode to U+FFFD.
52
+ const text = await readFile(path, 'latin1');
53
+ const schema = await schemaFor(detectVersion(text), options);
54
+ return parseIdf(text, schema, options);
55
+ }
56
+ /** Read and parse an epJSON file. */
57
+ export async function loadEpJson(path, options = {}) {
58
+ const text = await readFile(path, 'utf8');
59
+ const schema = await schemaFor(detectEpJsonVersion(text), options);
60
+ return parseEpJson(text, schema, options).document;
61
+ }
62
+ /** Write a document to an IDF file. */
63
+ export async function saveIdf(document, path, options = {}) {
64
+ await writeFile(path, writeIdf(document, options), 'latin1');
65
+ }
66
+ /** Write a document to an epJSON file. */
67
+ export async function saveEpJson(document, path, options = {}) {
68
+ await writeFile(path, writeEpJson(document, options), 'utf8');
69
+ }
70
+ //# sourceMappingURL=node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,114 @@
1
+ import type { SlimField, SlimType } from '@idfkit/schemas';
2
+ import { DATA, KEY, NAME, OWNER, SHAPE } from './internal.js';
3
+ import { type ObjectShape } from './shape.js';
4
+ /** A scalar field value. `undefined` means the field is absent. */
5
+ export type FieldValue = string | number | undefined;
6
+ /** One repeat of an extensible group, e.g. a single vertex. */
7
+ export type ExtensibleGroup = Record<string, string | number>;
8
+ /** Anything storable in a field slot. */
9
+ export type StoredValue = string | number | ExtensibleGroup[];
10
+ /** Field values accepted when constructing or updating an object. */
11
+ export type FieldValues = Record<string, StoredValue | null | undefined>;
12
+ /**
13
+ * Something that wants to know when an object changes.
14
+ *
15
+ * Implemented by `IDFDocument`. Declared as an interface so a detached object
16
+ * has no dependency on the document at all.
17
+ */
18
+ export interface ObjectOwner {
19
+ onFieldChanged(obj: IdfObject, field: string, previous: unknown, next: unknown): void;
20
+ onNameChanged(obj: IdfObject, previous: string, next: string): void;
21
+ }
22
+ /**
23
+ * A single EnergyPlus object.
24
+ *
25
+ * Field access is via real accessors installed on a per-type prototype, so
26
+ * `zone.ceiling_height` is an ordinary property read that TypeScript can see
27
+ * (given the generated interfaces) and V8 can inline. See `shape.ts`.
28
+ *
29
+ * Field names are epJSON names (`zone_name`, `outside_boundary_condition`),
30
+ * not the space-separated IDD names. That is a deliberate break from the Python
31
+ * library's IDF-to-Python conversion: epJSON names are already valid JS
32
+ * identifiers and valid TS interface keys, so using them directly means the
33
+ * on-disk name, the runtime key, and the static type all agree.
34
+ */
35
+ export declare class IdfObject {
36
+ readonly [DATA]: Record<string, StoredValue>;
37
+ readonly [SHAPE]: ObjectShape;
38
+ [OWNER]: ObjectOwner | undefined;
39
+ [NAME]: string;
40
+ [KEY]: string;
41
+ /**
42
+ * Objects are built through `IdfObject.create`, never `new`, because each
43
+ * instance's prototype depends on its object type.
44
+ */
45
+ private constructor();
46
+ static create(typeName: string, type: SlimType, name: string, values?: FieldValues): IdfObject;
47
+ /** Canonical object type name, e.g. `BuildingSurface:Detailed`. */
48
+ get typeName(): string;
49
+ /** Schema definition for this object's type. */
50
+ get schema(): SlimType;
51
+ /**
52
+ * The object's name, i.e. its key within its collection.
53
+ *
54
+ * Assigning propagates through the document: the collection is re-keyed and
55
+ * every field elsewhere in the model that referenced the old name is updated.
56
+ */
57
+ get name(): string;
58
+ set name(value: string);
59
+ /**
60
+ * The object's slot in its collection.
61
+ *
62
+ * Equals `name` for ordinary objects. Objects with no name, or with a blank
63
+ * name, get a synthetic key so they can still be stored and addressed.
64
+ */
65
+ get key(): string;
66
+ /** Whether this object type carries a name at all. */
67
+ get isNamed(): boolean;
68
+ /** Read a field by name. Untyped escape hatch for version-generic code. */
69
+ get(field: string): StoredValue | undefined;
70
+ /** Write a field by name, going through the same hooks as property access. */
71
+ set(field: string, value: StoredValue | null | undefined): void;
72
+ /** Apply several fields at once. */
73
+ update(values: FieldValues): this;
74
+ /** Whether the schema defines this field for this object type. */
75
+ hasField(field: string): boolean;
76
+ /** Schema definition for one field. */
77
+ fieldSchema(field: string): SlimField | undefined;
78
+ /** Field names in IDF positional order, excluding the name. */
79
+ get fieldNames(): readonly string[];
80
+ /** Field names that are actually set on this object. */
81
+ setFieldNames(): string[];
82
+ /**
83
+ * Repeat groups of the extensible section, e.g. the vertices of a surface.
84
+ *
85
+ * Returns a live array: pushing to it mutates the object.
86
+ */
87
+ get extensible(): ExtensibleGroup[];
88
+ /**
89
+ * Names this object's fields point at, paired with the field holding them.
90
+ *
91
+ * Extensible groups are included, with `index` naming the repeat the value
92
+ * sits in. Half the references in a real model live there.
93
+ */
94
+ outgoingReferences(): Array<{
95
+ field: string;
96
+ target: string;
97
+ index?: number;
98
+ }>;
99
+ /**
100
+ * Names this object contributes to the model's reference lists.
101
+ *
102
+ * Usually just `name`, but anonymous types like `FluidProperties:Name` carry
103
+ * their identity in an ordinary field instead, and other objects reference
104
+ * that value. Treating those as nameless makes every pointer at them look
105
+ * dangling.
106
+ */
107
+ declaredNames(): string[];
108
+ /** Detached deep copy, optionally renamed. Not attached to any document. */
109
+ clone(name?: string): IdfObject;
110
+ /** Plain epJSON body: field values only, without the name. */
111
+ toJSON(): Record<string, StoredValue>;
112
+ toString(): string;
113
+ }
114
+ //# sourceMappingURL=object.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"object.d.ts","sourceRoot":"","sources":["../src/object.ts"],"names":[],"mappings":"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"}
package/dist/object.js ADDED
@@ -0,0 +1,224 @@
1
+ import { DATA, KEY, NAME, OWNER, SHAPE } from './internal.js';
2
+ import { shapeFor } from './shape.js';
3
+ /**
4
+ * A single EnergyPlus object.
5
+ *
6
+ * Field access is via real accessors installed on a per-type prototype, so
7
+ * `zone.ceiling_height` is an ordinary property read that TypeScript can see
8
+ * (given the generated interfaces) and V8 can inline. See `shape.ts`.
9
+ *
10
+ * Field names are epJSON names (`zone_name`, `outside_boundary_condition`),
11
+ * not the space-separated IDD names. That is a deliberate break from the Python
12
+ * library's IDF-to-Python conversion: epJSON names are already valid JS
13
+ * identifiers and valid TS interface keys, so using them directly means the
14
+ * on-disk name, the runtime key, and the static type all agree.
15
+ */
16
+ export class IdfObject {
17
+ /**
18
+ * Objects are built through `IdfObject.create`, never `new`, because each
19
+ * instance's prototype depends on its object type.
20
+ */
21
+ constructor() {
22
+ throw new Error('Use IdfObject.create()');
23
+ }
24
+ static create(typeName, type, name, values = {}) {
25
+ const shape = shapeFor(typeName, type, IdfObject.prototype);
26
+ const obj = Object.create(shape.proto);
27
+ Object.defineProperty(obj, DATA, { value: Object.create(null) });
28
+ Object.defineProperty(obj, SHAPE, { value: shape });
29
+ Object.defineProperty(obj, OWNER, { value: undefined, writable: true });
30
+ Object.defineProperty(obj, NAME, { value: name, writable: true });
31
+ Object.defineProperty(obj, KEY, { value: name, writable: true });
32
+ for (const [field, value] of Object.entries(values)) {
33
+ if (value === undefined || value === null)
34
+ continue;
35
+ // Rejected rather than stored: an unrecognized name has no accessor and is
36
+ // dropped by every writer, so accepting it here means the caller reads
37
+ // their value back correctly and then loses it on save. `set()` already
38
+ // throws on the same input; this keeps the two paths in agreement.
39
+ if (!Object.hasOwn(type.p, field) && field !== shape.extensibleKey) {
40
+ throw new Error(`"${field}" is not a field of ${typeName}`);
41
+ }
42
+ obj[DATA][field] = value;
43
+ }
44
+ return obj;
45
+ }
46
+ /** Canonical object type name, e.g. `BuildingSurface:Detailed`. */
47
+ get typeName() {
48
+ return this[SHAPE].typeName;
49
+ }
50
+ /** Schema definition for this object's type. */
51
+ get schema() {
52
+ return this[SHAPE].type;
53
+ }
54
+ /**
55
+ * The object's name, i.e. its key within its collection.
56
+ *
57
+ * Assigning propagates through the document: the collection is re-keyed and
58
+ * every field elsewhere in the model that referenced the old name is updated.
59
+ */
60
+ get name() {
61
+ return this[NAME];
62
+ }
63
+ set name(value) {
64
+ const previous = this[NAME];
65
+ if (previous === value)
66
+ return;
67
+ const owner = this[OWNER];
68
+ if (owner === undefined) {
69
+ this[NAME] = value;
70
+ // The key has to move with the name, exactly as `onNameChanged` does for
71
+ // an attached object. Leaving it behind means a detached rename followed
72
+ // by `attach()` files the object under its old name, where no lookup by
73
+ // its current name can reach it.
74
+ if (value !== '')
75
+ this[KEY] = value;
76
+ return;
77
+ }
78
+ // The document performs the rename so it can reject duplicates before
79
+ // anything mutates, then rewrite referencing fields.
80
+ owner.onNameChanged(this, previous, value);
81
+ }
82
+ /**
83
+ * The object's slot in its collection.
84
+ *
85
+ * Equals `name` for ordinary objects. Objects with no name, or with a blank
86
+ * name, get a synthetic key so they can still be stored and addressed.
87
+ */
88
+ get key() {
89
+ return this[KEY];
90
+ }
91
+ /** Whether this object type carries a name at all. */
92
+ get isNamed() {
93
+ return this[SHAPE].named;
94
+ }
95
+ /** Read a field by name. Untyped escape hatch for version-generic code. */
96
+ get(field) {
97
+ return this[DATA][field];
98
+ }
99
+ /** Write a field by name, going through the same hooks as property access. */
100
+ set(field, value) {
101
+ if (!this.hasField(field)) {
102
+ throw new Error(`"${field}" is not a field of ${this.typeName}`);
103
+ }
104
+ // Route through the accessor so reference tracking fires exactly once.
105
+ this[field] = value ?? undefined;
106
+ }
107
+ /** Apply several fields at once. */
108
+ update(values) {
109
+ for (const [field, value] of Object.entries(values)) {
110
+ this.set(field, value ?? undefined);
111
+ }
112
+ return this;
113
+ }
114
+ /** Whether the schema defines this field for this object type. */
115
+ hasField(field) {
116
+ return Object.hasOwn(this[SHAPE].type.p, field) || field === this[SHAPE].extensibleKey;
117
+ }
118
+ /** Schema definition for one field. */
119
+ fieldSchema(field) {
120
+ return this[SHAPE].type.p[field];
121
+ }
122
+ /** Field names in IDF positional order, excluding the name. */
123
+ get fieldNames() {
124
+ return this[SHAPE].fields;
125
+ }
126
+ /** Field names that are actually set on this object. */
127
+ setFieldNames() {
128
+ return this[SHAPE].fields.filter((f) => this[DATA][f] !== undefined);
129
+ }
130
+ /**
131
+ * Repeat groups of the extensible section, e.g. the vertices of a surface.
132
+ *
133
+ * Returns a live array: pushing to it mutates the object.
134
+ */
135
+ get extensible() {
136
+ const key = this[SHAPE].extensibleKey;
137
+ if (key === undefined)
138
+ return [];
139
+ let list = this[DATA][key];
140
+ if (!Array.isArray(list)) {
141
+ list = [];
142
+ this[DATA][key] = list;
143
+ }
144
+ return list;
145
+ }
146
+ /**
147
+ * Names this object's fields point at, paired with the field holding them.
148
+ *
149
+ * Extensible groups are included, with `index` naming the repeat the value
150
+ * sits in. Half the references in a real model live there.
151
+ */
152
+ outgoingReferences() {
153
+ const out = [];
154
+ for (const field of this[SHAPE].refFields) {
155
+ const value = this[DATA][field];
156
+ if (typeof value === 'string' && value !== '')
157
+ out.push({ field, target: value });
158
+ }
159
+ const extensibleRefs = this[SHAPE].extensibleRefFields;
160
+ const key = this[SHAPE].extensibleKey;
161
+ if (extensibleRefs.length > 0 && key !== undefined) {
162
+ // Read through DATA rather than the `extensible` getter, which
163
+ // materializes an empty array as a side effect.
164
+ const list = this[DATA][key];
165
+ if (Array.isArray(list)) {
166
+ list.forEach((group, index) => {
167
+ for (const field of extensibleRefs) {
168
+ const value = group[field];
169
+ if (typeof value === 'string' && value !== '')
170
+ out.push({ field, target: value, index });
171
+ }
172
+ });
173
+ }
174
+ }
175
+ return out;
176
+ }
177
+ /**
178
+ * Names this object contributes to the model's reference lists.
179
+ *
180
+ * Usually just `name`, but anonymous types like `FluidProperties:Name` carry
181
+ * their identity in an ordinary field instead, and other objects reference
182
+ * that value. Treating those as nameless makes every pointer at them look
183
+ * dangling.
184
+ */
185
+ declaredNames() {
186
+ const out = [];
187
+ if (this[NAME] !== '')
188
+ out.push(this[NAME]);
189
+ for (const field of this[SHAPE].keyFields) {
190
+ const value = this[DATA][field];
191
+ if (typeof value === 'string' && value !== '')
192
+ out.push(value);
193
+ }
194
+ return out;
195
+ }
196
+ /** Detached deep copy, optionally renamed. Not attached to any document. */
197
+ clone(name = this[NAME]) {
198
+ const copy = IdfObject.create(this.typeName, this[SHAPE].type, name);
199
+ for (const [field, value] of Object.entries(this[DATA])) {
200
+ copy[DATA][field] = Array.isArray(value) ? value.map((group) => ({ ...group })) : value;
201
+ }
202
+ return copy;
203
+ }
204
+ /** Plain epJSON body: field values only, without the name. */
205
+ toJSON() {
206
+ const out = {};
207
+ for (const field of this[SHAPE].fields) {
208
+ const value = this[DATA][field];
209
+ if (value !== undefined)
210
+ out[field] = value;
211
+ }
212
+ const key = this[SHAPE].extensibleKey;
213
+ if (key !== undefined) {
214
+ const list = this[DATA][key];
215
+ if (Array.isArray(list) && list.length > 0)
216
+ out[key] = list.map((g) => ({ ...g }));
217
+ }
218
+ return out;
219
+ }
220
+ toString() {
221
+ return `${this.typeName}(${this[NAME]})`;
222
+ }
223
+ }
224
+ //# sourceMappingURL=object.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"object.js","sourceRoot":"","sources":["../src/object.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { Schema } from '@idfkit/schemas';
2
+ import type { AnyTypeMap, UntypedMap } from '../typemap.js';
3
+ import type { ParseOptions, ParseResult } from './idf.js';
4
+ /** epJSON document shape: type -> name -> field values. */
5
+ export type EpJson = Record<string, Record<string, Record<string, unknown>>>;
6
+ /**
7
+ * Parse epJSON into a document.
8
+ *
9
+ * Trivial next to the IDF path, which is the point: epJSON is already named and
10
+ * typed, so there is no positional mapping and no coercion to do. Most of the
11
+ * work here is deciding what to do about input the schema does not recognize.
12
+ */
13
+ export declare function parseEpJson<M extends AnyTypeMap = UntypedMap>(source: string | EpJson, schema: Schema, options?: ParseOptions): ParseResult<M>;
14
+ /** Read the version identifier from epJSON without a schema. */
15
+ export declare function detectEpJsonVersion(source: string | EpJson): string | undefined;
16
+ //# sourceMappingURL=epjson.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"epjson.d.ts","sourceRoot":"","sources":["../../src/parse/epjson.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAI9C,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,KAAK,EAAmB,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAG3E,2DAA2D;AAC3D,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AAE7E;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EAC3D,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,YAAiB,GACzB,WAAW,CAAC,CAAC,CAAC,CA6DhB;AAED,gEAAgE;AAChE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAgB/E"}
@@ -0,0 +1,91 @@
1
+ import { IDFDocument } from '../document.js';
2
+ import { IdfParseError } from './idf.js';
3
+ /**
4
+ * Parse epJSON into a document.
5
+ *
6
+ * Trivial next to the IDF path, which is the point: epJSON is already named and
7
+ * typed, so there is no positional mapping and no coercion to do. Most of the
8
+ * work here is deciding what to do about input the schema does not recognize.
9
+ */
10
+ export function parseEpJson(source, schema, options = {}) {
11
+ const strict = options.strict ?? true;
12
+ const diagnostics = [];
13
+ const report = (diagnostic) => {
14
+ if (strict)
15
+ throw new IdfParseError(diagnostic);
16
+ diagnostics.push(diagnostic);
17
+ options.onDiagnostic?.(diagnostic);
18
+ };
19
+ let root;
20
+ try {
21
+ root = typeof source === 'string' ? JSON.parse(source) : source;
22
+ }
23
+ catch (error) {
24
+ throw new IdfParseError({
25
+ message: `Invalid JSON: ${error instanceof Error ? error.message : String(error)}`,
26
+ line: 1,
27
+ });
28
+ }
29
+ const document = new IDFDocument(schema);
30
+ for (const [typeName, body] of Object.entries(root)) {
31
+ const canonical = schema.resolve(typeName);
32
+ if (canonical === undefined) {
33
+ report({
34
+ message: `Unknown object type "${typeName}" in EnergyPlus ${schema.version}`,
35
+ line: 1,
36
+ typeName,
37
+ });
38
+ continue;
39
+ }
40
+ const definition = schema.require(canonical);
41
+ for (const [name, fields] of Object.entries(body ?? {})) {
42
+ const values = {};
43
+ for (const [field, value] of Object.entries(fields ?? {})) {
44
+ if (value === null || value === undefined)
45
+ continue;
46
+ if (!Object.hasOwn(definition.p, field) && field !== definition.x?.key) {
47
+ report({
48
+ message: `Unknown field "${field}" on ${canonical}`,
49
+ line: 1,
50
+ typeName: canonical,
51
+ });
52
+ continue;
53
+ }
54
+ values[field] = value;
55
+ }
56
+ try {
57
+ document.addRaw(canonical, definition.anon === 1 ? null : name, values);
58
+ }
59
+ catch (error) {
60
+ report({
61
+ message: error instanceof Error ? error.message : String(error),
62
+ line: 1,
63
+ typeName: canonical,
64
+ });
65
+ }
66
+ }
67
+ }
68
+ return { document, diagnostics };
69
+ }
70
+ /** Read the version identifier from epJSON without a schema. */
71
+ export function detectEpJsonVersion(source) {
72
+ let root;
73
+ try {
74
+ root = typeof source === 'string' ? JSON.parse(source) : source;
75
+ }
76
+ catch {
77
+ return undefined;
78
+ }
79
+ const versions = root['Version'];
80
+ if (versions === undefined)
81
+ return undefined;
82
+ const first = Object.values(versions)[0];
83
+ const raw = first?.['version_identifier'];
84
+ if (raw === undefined)
85
+ return undefined;
86
+ const parts = String(raw)
87
+ .split('.')
88
+ .map((p) => Number(p) || 0);
89
+ return `${parts[0] ?? 0}.${parts[1] ?? 0}.${parts[2] ?? 0}`;
90
+ }
91
+ //# sourceMappingURL=epjson.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"epjson.js","sourceRoot":"","sources":["../../src/parse/epjson.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import type { Schema } from '@idfkit/schemas';
2
+ import { IDFDocument } from '../document.js';
3
+ import type { AnyTypeMap, UntypedMap } from '../typemap.js';
4
+ import { type LexDiagnostic } from './lexer.js';
5
+ export interface ParseDiagnostic extends LexDiagnostic {
6
+ /** Object type the problem occurred in, when known. */
7
+ typeName?: string;
8
+ }
9
+ export interface ParseOptions {
10
+ /**
11
+ * Throw on the first diagnostic instead of collecting them.
12
+ * @defaultValue true
13
+ */
14
+ strict?: boolean;
15
+ /** Collects diagnostics when `strict` is false. */
16
+ onDiagnostic?: (diagnostic: ParseDiagnostic) => void;
17
+ }
18
+ export interface ParseResult<M extends AnyTypeMap = UntypedMap> {
19
+ document: IDFDocument<M>;
20
+ diagnostics: ParseDiagnostic[];
21
+ }
22
+ /**
23
+ * Parse IDF text into a document.
24
+ *
25
+ * Synchronous and pure: text in, document out, no I/O. Everything that touches
26
+ * the filesystem or network lives at the edges (`@idfkit/core/node`), so this
27
+ * function behaves identically in Node, a browser, and a worker. The schema
28
+ * must already be loaded, which is the one genuinely async step.
29
+ */
30
+ export declare function parseIdf<M extends AnyTypeMap = UntypedMap>(text: string, schema: Schema, options?: ParseOptions): ParseResult<M>;
31
+ export declare class IdfParseError extends Error {
32
+ readonly line: number;
33
+ readonly typeName: string | undefined;
34
+ constructor(diagnostic: ParseDiagnostic);
35
+ }
36
+ /**
37
+ * Read the version identifier from IDF text without a schema.
38
+ *
39
+ * Chicken-and-egg: choosing the schema requires knowing the version, and the
40
+ * version lives inside the file. This does the minimum scan needed to break
41
+ * the cycle, and does not validate anything else.
42
+ */
43
+ export declare function detectVersion(text: string): string | undefined;
44
+ //# sourceMappingURL=idf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idf.d.ts","sourceRoot":"","sources":["../../src/parse/idf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAY,MAAM,iBAAiB,CAAC;AAExD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAO,KAAK,aAAa,EAAkB,MAAM,YAAY,CAAC;AAErE,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACpD,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,mDAAmD;IACnD,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,eAAe,KAAK,IAAI,CAAC;CACtD;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU;IAC5D,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACzB,WAAW,EAAE,eAAe,EAAE,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EACxD,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,YAAiB,GACzB,WAAW,CAAC,CAAC,CAAC,CAwChB;AAkGD,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;gBAE1B,UAAU,EAAE,eAAe;CAMxC;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAc9D"}