@ifc-lite/codegen 1.15.3 → 1.15.4
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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +48 -0
- package/INTEGRATION.md +6 -0
- package/dist/serialization-generator.d.ts +7 -2
- package/dist/serialization-generator.d.ts.map +1 -1
- package/dist/serialization-generator.js +30 -301
- package/dist/serialization-generator.js.map +1 -1
- package/generated/ifc4/serializers.ts +27 -298
- package/generated/ifc4x3/serializers.ts +27 -298
- package/package.json +5 -4
- package/src/serialization-generator.ts +36 -305
- package/test/serialization-generator.test.ts +65 -0
|
@@ -6,317 +6,46 @@
|
|
|
6
6
|
* IFC Serialization Support
|
|
7
7
|
* Generated from EXPRESS schema: IFC4_ADD2_TC1
|
|
8
8
|
*
|
|
9
|
-
*
|
|
9
|
+
* Thin binding over the shared, schema-agnostic STEP serializer in
|
|
10
|
+
* `@ifc-lite/data`. All serialization logic lives there (single source of
|
|
11
|
+
* truth); only this bundle's `SCHEMA_REGISTRY` is bound to the registry-coupled
|
|
12
|
+
* helpers below.
|
|
10
13
|
*
|
|
11
14
|
* DO NOT EDIT - This file is auto-generated
|
|
12
15
|
*/
|
|
13
16
|
|
|
14
17
|
import { SCHEMA_REGISTRY } from './schema-registry.js';
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Enum value (.VALUE.)
|
|
38
|
-
*/
|
|
39
|
-
export interface EnumValue {
|
|
40
|
-
enum: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Check if value is an entity reference
|
|
45
|
-
*/
|
|
46
|
-
export function isEntityRef(value: unknown): value is EntityRef {
|
|
47
|
-
return typeof value === 'object' && value !== null && 'ref' in value;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Check if value is an enum value
|
|
52
|
-
*/
|
|
53
|
-
export function isEnumValue(value: unknown): value is EnumValue {
|
|
54
|
-
return typeof value === 'object' && value !== null && 'enum' in value;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Create an entity reference
|
|
59
|
-
*/
|
|
60
|
-
export function ref(id: number): EntityRef {
|
|
61
|
-
return { ref: id };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Create an enum value
|
|
66
|
-
*/
|
|
67
|
-
export function enumVal(value: string): EnumValue {
|
|
68
|
-
return { enum: value };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Base interface for serializable entities
|
|
73
|
-
*/
|
|
74
|
-
export interface StepEntity {
|
|
75
|
-
/** Express ID (#123) */
|
|
76
|
-
expressId: number;
|
|
77
|
-
/** IFC type name */
|
|
78
|
-
type: string;
|
|
79
|
-
/** Attribute values */
|
|
80
|
-
[key: string]: unknown;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Serialize a single value to STEP format
|
|
85
|
-
*/
|
|
86
|
-
export function serializeValue(value: StepValue): string {
|
|
87
|
-
// Null/undefined -> $
|
|
88
|
-
if (value === null || value === undefined) {
|
|
89
|
-
return '$';
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Derived value -> *
|
|
93
|
-
if (value === '*') {
|
|
94
|
-
return '*';
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Boolean
|
|
98
|
-
if (typeof value === 'boolean') {
|
|
99
|
-
return value ? '.T.' : '.F.';
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Number
|
|
103
|
-
if (typeof value === 'number') {
|
|
104
|
-
if (!Number.isFinite(value)) {
|
|
105
|
-
return '$';
|
|
106
|
-
}
|
|
107
|
-
// Use exponential notation for large/small numbers
|
|
108
|
-
if (Math.abs(value) > 1e10 || (Math.abs(value) < 1e-10 && value !== 0)) {
|
|
109
|
-
return value.toExponential(10).toUpperCase().replace('E+', 'E');
|
|
110
|
-
}
|
|
111
|
-
// Otherwise use fixed notation
|
|
112
|
-
const str = value.toString();
|
|
113
|
-
// Ensure there's a decimal point for REAL values
|
|
114
|
-
return str.includes('.') ? str : str + '.';
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// String
|
|
118
|
-
if (typeof value === 'string') {
|
|
119
|
-
return "'" + escapeStepString(value) + "'";
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Entity reference
|
|
123
|
-
if (isEntityRef(value)) {
|
|
124
|
-
return '#' + value.ref;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Enum value
|
|
128
|
-
if (isEnumValue(value)) {
|
|
129
|
-
return '.' + value.enum + '.';
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Array/List
|
|
133
|
-
if (Array.isArray(value)) {
|
|
134
|
-
if (value.length === 0) {
|
|
135
|
-
return '()';
|
|
136
|
-
}
|
|
137
|
-
return '(' + value.map(v => serializeValue(v as StepValue)).join(',') + ')';
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Object (shouldn't happen for valid STEP values)
|
|
141
|
-
return '$';
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Escape a string for STEP format
|
|
146
|
-
*/
|
|
147
|
-
function escapeStepString(str: string): string {
|
|
148
|
-
return str
|
|
149
|
-
.replace(/\\/g, '\\\\') // Backslash
|
|
150
|
-
.replace(/'/g, "''"); // Single quote
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Serialize an entity to a STEP line
|
|
18
|
+
import {
|
|
19
|
+
generateHeader,
|
|
20
|
+
generateStepFileWithRegistry,
|
|
21
|
+
toStepLineWithRegistry,
|
|
22
|
+
type StepEntity,
|
|
23
|
+
} from '@ifc-lite/data';
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
isEntityRef,
|
|
27
|
+
isEnumValue,
|
|
28
|
+
ref,
|
|
29
|
+
enumVal,
|
|
30
|
+
serializeValue,
|
|
31
|
+
generateHeader,
|
|
32
|
+
parseStepValue,
|
|
33
|
+
} from '@ifc-lite/data';
|
|
34
|
+
export type { StepValue, EntityRef, EnumValue, StepEntity } from '@ifc-lite/data';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Serialize an entity to a STEP line (bound to this bundle's schema).
|
|
155
38
|
*/
|
|
156
39
|
export function toStepLine(entity: StepEntity): string {
|
|
157
|
-
|
|
158
|
-
if (!schema) {
|
|
159
|
-
throw new Error(`Unknown entity type: ${entity.type}`);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Get all attributes in order
|
|
163
|
-
const values: string[] = [];
|
|
164
|
-
for (const attr of schema.allAttributes) {
|
|
165
|
-
const value = entity[attr.name];
|
|
166
|
-
values.push(serializeValue(value as StepValue));
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return `#${entity.expressId}=${entity.type.toUpperCase()}(${values.join(',')});`;
|
|
40
|
+
return toStepLineWithRegistry(SCHEMA_REGISTRY, entity);
|
|
170
41
|
}
|
|
171
42
|
|
|
172
43
|
/**
|
|
173
|
-
* Generate STEP file
|
|
174
|
-
*/
|
|
175
|
-
export function generateHeader(options: {
|
|
176
|
-
description?: string;
|
|
177
|
-
author?: string;
|
|
178
|
-
organization?: string;
|
|
179
|
-
application?: string;
|
|
180
|
-
schema: 'IFC2X3' | 'IFC4' | 'IFC4X3' | 'IFC5';
|
|
181
|
-
filename?: string;
|
|
182
|
-
}): string {
|
|
183
|
-
const now = new Date().toISOString().replace(/[-:]/g, '').split('.')[0];
|
|
184
|
-
const desc = options.description || 'ViewDefinition [CoordinationView]';
|
|
185
|
-
const author = options.author || '';
|
|
186
|
-
const org = options.organization || '';
|
|
187
|
-
const app = options.application || 'ifc-lite';
|
|
188
|
-
const filename = options.filename || 'output.ifc';
|
|
189
|
-
|
|
190
|
-
return `ISO-10303-21;
|
|
191
|
-
HEADER;
|
|
192
|
-
FILE_DESCRIPTION('${desc}','2;1');
|
|
193
|
-
FILE_NAME('${filename}','${now}',('${author}'),('${org}'),'${app}','${app}','');
|
|
194
|
-
FILE_SCHEMA(('${options.schema}'));
|
|
195
|
-
ENDSEC;
|
|
196
|
-
`;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Generate complete STEP file content
|
|
44
|
+
* Generate complete STEP file content (bound to this bundle's schema).
|
|
201
45
|
*/
|
|
202
46
|
export function generateStepFile(
|
|
203
47
|
entities: StepEntity[],
|
|
204
48
|
options: Parameters<typeof generateHeader>[0]
|
|
205
49
|
): string {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
// Sort entities by ID for deterministic output
|
|
209
|
-
const sorted = [...entities].sort((a, b) => a.expressId - b.expressId);
|
|
210
|
-
|
|
211
|
-
const data = sorted.map(e => toStepLine(e)).join('\n');
|
|
212
|
-
|
|
213
|
-
return `${header}DATA;
|
|
214
|
-
${data}
|
|
215
|
-
ENDSEC;
|
|
216
|
-
END-ISO-10303-21;
|
|
217
|
-
`;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Parse a STEP value from string
|
|
222
|
-
*/
|
|
223
|
-
export function parseStepValue(str: string): StepValue {
|
|
224
|
-
str = str.trim();
|
|
225
|
-
|
|
226
|
-
// Null
|
|
227
|
-
if (str === '$') {
|
|
228
|
-
return null;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Derived
|
|
232
|
-
if (str === '*') {
|
|
233
|
-
return '*' as unknown as StepValue;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Boolean
|
|
237
|
-
if (str === '.T.') {
|
|
238
|
-
return true;
|
|
239
|
-
}
|
|
240
|
-
if (str === '.F.') {
|
|
241
|
-
return false;
|
|
242
|
-
}
|
|
243
|
-
if (str === '.U.') {
|
|
244
|
-
return null; // Unknown/indeterminate
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Entity reference
|
|
248
|
-
if (str.startsWith('#')) {
|
|
249
|
-
return { ref: parseInt(str.substring(1), 10) };
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// Enum
|
|
253
|
-
if (str.startsWith('.') && str.endsWith('.')) {
|
|
254
|
-
return { enum: str.substring(1, str.length - 1) };
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// String
|
|
258
|
-
if (str.startsWith("'") && str.endsWith("'")) {
|
|
259
|
-
return unescapeStepString(str.substring(1, str.length - 1));
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// List
|
|
263
|
-
if (str.startsWith('(') && str.endsWith(')')) {
|
|
264
|
-
return parseStepList(str);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Number
|
|
268
|
-
const num = parseFloat(str);
|
|
269
|
-
if (!isNaN(num)) {
|
|
270
|
-
return num;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// Unknown
|
|
274
|
-
return str;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Parse a STEP list
|
|
279
|
-
*/
|
|
280
|
-
function parseStepList(str: string): StepValue[] {
|
|
281
|
-
// Remove outer parentheses
|
|
282
|
-
const inner = str.substring(1, str.length - 1).trim();
|
|
283
|
-
if (inner === '') {
|
|
284
|
-
return [];
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
const values: StepValue[] = [];
|
|
288
|
-
let depth = 0;
|
|
289
|
-
let current = '';
|
|
290
|
-
|
|
291
|
-
for (let i = 0; i < inner.length; i++) {
|
|
292
|
-
const char = inner[i];
|
|
293
|
-
|
|
294
|
-
if (char === '(' || char === '[') {
|
|
295
|
-
depth++;
|
|
296
|
-
current += char;
|
|
297
|
-
} else if (char === ')' || char === ']') {
|
|
298
|
-
depth--;
|
|
299
|
-
current += char;
|
|
300
|
-
} else if (char === ',' && depth === 0) {
|
|
301
|
-
values.push(parseStepValue(current));
|
|
302
|
-
current = '';
|
|
303
|
-
} else {
|
|
304
|
-
current += char;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (current.trim()) {
|
|
309
|
-
values.push(parseStepValue(current));
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
return values;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Unescape a STEP string
|
|
317
|
-
*/
|
|
318
|
-
function unescapeStepString(str: string): string {
|
|
319
|
-
return str
|
|
320
|
-
.replace(/''/g, "'")
|
|
321
|
-
.replace(/\\\\/g, '\\');
|
|
50
|
+
return generateStepFileWithRegistry(SCHEMA_REGISTRY, entities, options);
|
|
322
51
|
}
|
|
@@ -6,317 +6,46 @@
|
|
|
6
6
|
* IFC Serialization Support
|
|
7
7
|
* Generated from EXPRESS schema: IFC4X3_DEV_923b0514
|
|
8
8
|
*
|
|
9
|
-
*
|
|
9
|
+
* Thin binding over the shared, schema-agnostic STEP serializer in
|
|
10
|
+
* `@ifc-lite/data`. All serialization logic lives there (single source of
|
|
11
|
+
* truth); only this bundle's `SCHEMA_REGISTRY` is bound to the registry-coupled
|
|
12
|
+
* helpers below.
|
|
10
13
|
*
|
|
11
14
|
* DO NOT EDIT - This file is auto-generated
|
|
12
15
|
*/
|
|
13
16
|
|
|
14
17
|
import { SCHEMA_REGISTRY } from './schema-registry.js';
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Enum value (.VALUE.)
|
|
38
|
-
*/
|
|
39
|
-
export interface EnumValue {
|
|
40
|
-
enum: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Check if value is an entity reference
|
|
45
|
-
*/
|
|
46
|
-
export function isEntityRef(value: unknown): value is EntityRef {
|
|
47
|
-
return typeof value === 'object' && value !== null && 'ref' in value;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Check if value is an enum value
|
|
52
|
-
*/
|
|
53
|
-
export function isEnumValue(value: unknown): value is EnumValue {
|
|
54
|
-
return typeof value === 'object' && value !== null && 'enum' in value;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Create an entity reference
|
|
59
|
-
*/
|
|
60
|
-
export function ref(id: number): EntityRef {
|
|
61
|
-
return { ref: id };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Create an enum value
|
|
66
|
-
*/
|
|
67
|
-
export function enumVal(value: string): EnumValue {
|
|
68
|
-
return { enum: value };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Base interface for serializable entities
|
|
73
|
-
*/
|
|
74
|
-
export interface StepEntity {
|
|
75
|
-
/** Express ID (#123) */
|
|
76
|
-
expressId: number;
|
|
77
|
-
/** IFC type name */
|
|
78
|
-
type: string;
|
|
79
|
-
/** Attribute values */
|
|
80
|
-
[key: string]: unknown;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Serialize a single value to STEP format
|
|
85
|
-
*/
|
|
86
|
-
export function serializeValue(value: StepValue): string {
|
|
87
|
-
// Null/undefined -> $
|
|
88
|
-
if (value === null || value === undefined) {
|
|
89
|
-
return '$';
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Derived value -> *
|
|
93
|
-
if (value === '*') {
|
|
94
|
-
return '*';
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Boolean
|
|
98
|
-
if (typeof value === 'boolean') {
|
|
99
|
-
return value ? '.T.' : '.F.';
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Number
|
|
103
|
-
if (typeof value === 'number') {
|
|
104
|
-
if (!Number.isFinite(value)) {
|
|
105
|
-
return '$';
|
|
106
|
-
}
|
|
107
|
-
// Use exponential notation for large/small numbers
|
|
108
|
-
if (Math.abs(value) > 1e10 || (Math.abs(value) < 1e-10 && value !== 0)) {
|
|
109
|
-
return value.toExponential(10).toUpperCase().replace('E+', 'E');
|
|
110
|
-
}
|
|
111
|
-
// Otherwise use fixed notation
|
|
112
|
-
const str = value.toString();
|
|
113
|
-
// Ensure there's a decimal point for REAL values
|
|
114
|
-
return str.includes('.') ? str : str + '.';
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// String
|
|
118
|
-
if (typeof value === 'string') {
|
|
119
|
-
return "'" + escapeStepString(value) + "'";
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Entity reference
|
|
123
|
-
if (isEntityRef(value)) {
|
|
124
|
-
return '#' + value.ref;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Enum value
|
|
128
|
-
if (isEnumValue(value)) {
|
|
129
|
-
return '.' + value.enum + '.';
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Array/List
|
|
133
|
-
if (Array.isArray(value)) {
|
|
134
|
-
if (value.length === 0) {
|
|
135
|
-
return '()';
|
|
136
|
-
}
|
|
137
|
-
return '(' + value.map(v => serializeValue(v as StepValue)).join(',') + ')';
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Object (shouldn't happen for valid STEP values)
|
|
141
|
-
return '$';
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Escape a string for STEP format
|
|
146
|
-
*/
|
|
147
|
-
function escapeStepString(str: string): string {
|
|
148
|
-
return str
|
|
149
|
-
.replace(/\\/g, '\\\\') // Backslash
|
|
150
|
-
.replace(/'/g, "''"); // Single quote
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Serialize an entity to a STEP line
|
|
18
|
+
import {
|
|
19
|
+
generateHeader,
|
|
20
|
+
generateStepFileWithRegistry,
|
|
21
|
+
toStepLineWithRegistry,
|
|
22
|
+
type StepEntity,
|
|
23
|
+
} from '@ifc-lite/data';
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
isEntityRef,
|
|
27
|
+
isEnumValue,
|
|
28
|
+
ref,
|
|
29
|
+
enumVal,
|
|
30
|
+
serializeValue,
|
|
31
|
+
generateHeader,
|
|
32
|
+
parseStepValue,
|
|
33
|
+
} from '@ifc-lite/data';
|
|
34
|
+
export type { StepValue, EntityRef, EnumValue, StepEntity } from '@ifc-lite/data';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Serialize an entity to a STEP line (bound to this bundle's schema).
|
|
155
38
|
*/
|
|
156
39
|
export function toStepLine(entity: StepEntity): string {
|
|
157
|
-
|
|
158
|
-
if (!schema) {
|
|
159
|
-
throw new Error(`Unknown entity type: ${entity.type}`);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Get all attributes in order
|
|
163
|
-
const values: string[] = [];
|
|
164
|
-
for (const attr of schema.allAttributes) {
|
|
165
|
-
const value = entity[attr.name];
|
|
166
|
-
values.push(serializeValue(value as StepValue));
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return `#${entity.expressId}=${entity.type.toUpperCase()}(${values.join(',')});`;
|
|
40
|
+
return toStepLineWithRegistry(SCHEMA_REGISTRY, entity);
|
|
170
41
|
}
|
|
171
42
|
|
|
172
43
|
/**
|
|
173
|
-
* Generate STEP file
|
|
174
|
-
*/
|
|
175
|
-
export function generateHeader(options: {
|
|
176
|
-
description?: string;
|
|
177
|
-
author?: string;
|
|
178
|
-
organization?: string;
|
|
179
|
-
application?: string;
|
|
180
|
-
schema: 'IFC2X3' | 'IFC4' | 'IFC4X3' | 'IFC5';
|
|
181
|
-
filename?: string;
|
|
182
|
-
}): string {
|
|
183
|
-
const now = new Date().toISOString().replace(/[-:]/g, '').split('.')[0];
|
|
184
|
-
const desc = options.description || 'ViewDefinition [CoordinationView]';
|
|
185
|
-
const author = options.author || '';
|
|
186
|
-
const org = options.organization || '';
|
|
187
|
-
const app = options.application || 'ifc-lite';
|
|
188
|
-
const filename = options.filename || 'output.ifc';
|
|
189
|
-
|
|
190
|
-
return `ISO-10303-21;
|
|
191
|
-
HEADER;
|
|
192
|
-
FILE_DESCRIPTION('${desc}','2;1');
|
|
193
|
-
FILE_NAME('${filename}','${now}',('${author}'),('${org}'),'${app}','${app}','');
|
|
194
|
-
FILE_SCHEMA(('${options.schema}'));
|
|
195
|
-
ENDSEC;
|
|
196
|
-
`;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Generate complete STEP file content
|
|
44
|
+
* Generate complete STEP file content (bound to this bundle's schema).
|
|
201
45
|
*/
|
|
202
46
|
export function generateStepFile(
|
|
203
47
|
entities: StepEntity[],
|
|
204
48
|
options: Parameters<typeof generateHeader>[0]
|
|
205
49
|
): string {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
// Sort entities by ID for deterministic output
|
|
209
|
-
const sorted = [...entities].sort((a, b) => a.expressId - b.expressId);
|
|
210
|
-
|
|
211
|
-
const data = sorted.map(e => toStepLine(e)).join('\n');
|
|
212
|
-
|
|
213
|
-
return `${header}DATA;
|
|
214
|
-
${data}
|
|
215
|
-
ENDSEC;
|
|
216
|
-
END-ISO-10303-21;
|
|
217
|
-
`;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Parse a STEP value from string
|
|
222
|
-
*/
|
|
223
|
-
export function parseStepValue(str: string): StepValue {
|
|
224
|
-
str = str.trim();
|
|
225
|
-
|
|
226
|
-
// Null
|
|
227
|
-
if (str === '$') {
|
|
228
|
-
return null;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Derived
|
|
232
|
-
if (str === '*') {
|
|
233
|
-
return '*' as unknown as StepValue;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Boolean
|
|
237
|
-
if (str === '.T.') {
|
|
238
|
-
return true;
|
|
239
|
-
}
|
|
240
|
-
if (str === '.F.') {
|
|
241
|
-
return false;
|
|
242
|
-
}
|
|
243
|
-
if (str === '.U.') {
|
|
244
|
-
return null; // Unknown/indeterminate
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Entity reference
|
|
248
|
-
if (str.startsWith('#')) {
|
|
249
|
-
return { ref: parseInt(str.substring(1), 10) };
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// Enum
|
|
253
|
-
if (str.startsWith('.') && str.endsWith('.')) {
|
|
254
|
-
return { enum: str.substring(1, str.length - 1) };
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// String
|
|
258
|
-
if (str.startsWith("'") && str.endsWith("'")) {
|
|
259
|
-
return unescapeStepString(str.substring(1, str.length - 1));
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// List
|
|
263
|
-
if (str.startsWith('(') && str.endsWith(')')) {
|
|
264
|
-
return parseStepList(str);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Number
|
|
268
|
-
const num = parseFloat(str);
|
|
269
|
-
if (!isNaN(num)) {
|
|
270
|
-
return num;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// Unknown
|
|
274
|
-
return str;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Parse a STEP list
|
|
279
|
-
*/
|
|
280
|
-
function parseStepList(str: string): StepValue[] {
|
|
281
|
-
// Remove outer parentheses
|
|
282
|
-
const inner = str.substring(1, str.length - 1).trim();
|
|
283
|
-
if (inner === '') {
|
|
284
|
-
return [];
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
const values: StepValue[] = [];
|
|
288
|
-
let depth = 0;
|
|
289
|
-
let current = '';
|
|
290
|
-
|
|
291
|
-
for (let i = 0; i < inner.length; i++) {
|
|
292
|
-
const char = inner[i];
|
|
293
|
-
|
|
294
|
-
if (char === '(' || char === '[') {
|
|
295
|
-
depth++;
|
|
296
|
-
current += char;
|
|
297
|
-
} else if (char === ')' || char === ']') {
|
|
298
|
-
depth--;
|
|
299
|
-
current += char;
|
|
300
|
-
} else if (char === ',' && depth === 0) {
|
|
301
|
-
values.push(parseStepValue(current));
|
|
302
|
-
current = '';
|
|
303
|
-
} else {
|
|
304
|
-
current += char;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (current.trim()) {
|
|
309
|
-
values.push(parseStepValue(current));
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
return values;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Unescape a STEP string
|
|
317
|
-
*/
|
|
318
|
-
function unescapeStepString(str: string): string {
|
|
319
|
-
return str
|
|
320
|
-
.replace(/''/g, "'")
|
|
321
|
-
.replace(/\\\\/g, '\\');
|
|
50
|
+
return generateStepFileWithRegistry(SCHEMA_REGISTRY, entities, options);
|
|
322
51
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ifc-lite/codegen",
|
|
3
|
-
"version": "1.15.
|
|
3
|
+
"version": "1.15.4",
|
|
4
4
|
"description": "TypeScript code generator from IFC EXPRESS schemas",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -19,10 +19,11 @@
|
|
|
19
19
|
"author": "",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"commander": "^15.0.0"
|
|
22
|
+
"commander": "^15.0.0",
|
|
23
|
+
"@ifc-lite/data": "^2.1.0"
|
|
23
24
|
},
|
|
24
25
|
"devDependencies": {
|
|
25
|
-
"@types/node": "^25.9.
|
|
26
|
+
"@types/node": "^25.9.3",
|
|
26
27
|
"typescript": "^6.0.3",
|
|
27
28
|
"vitest": "^4.1.0"
|
|
28
29
|
},
|
|
@@ -31,7 +32,7 @@
|
|
|
31
32
|
"dev": "pnpm exec tsc --watch",
|
|
32
33
|
"test": "vitest run",
|
|
33
34
|
"generate": "node dist/cli.js",
|
|
34
|
-
"generate:ifc4": "node dist/cli.js schemas/
|
|
35
|
+
"generate:ifc4": "node dist/cli.js schemas/IFC4_ADD2_TC1.exp -o generated/ifc4",
|
|
35
36
|
"generate:ifc4x3": "node dist/cli.js schemas/IFC4X3.exp -o generated/ifc4x3"
|
|
36
37
|
}
|
|
37
38
|
}
|