@bitbybit-dev/ifc 0.0.0-stage → 1.5.0-rc.0

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 (242) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +42 -0
  3. package/README.md +92 -2
  4. package/index.d.ts +1 -0
  5. package/index.js +1 -0
  6. package/lib/api/dto-registry.d.ts +8 -0
  7. package/lib/api/dto-registry.js +109 -0
  8. package/lib/api/ifc-service.d.ts +109 -0
  9. package/lib/api/ifc-service.js +55 -0
  10. package/lib/api/inputs/base-inputs.d.ts +5 -0
  11. package/lib/api/inputs/base-inputs.js +5 -0
  12. package/lib/api/inputs/ifc-inputs.d.ts +2727 -0
  13. package/lib/api/inputs/ifc-inputs.js +2498 -0
  14. package/lib/api/inputs/index.d.ts +3 -0
  15. package/lib/api/inputs/index.js +3 -0
  16. package/lib/api/resolved-inputs/index.d.ts +70 -0
  17. package/lib/api/resolved-inputs/index.js +1 -0
  18. package/lib/api/services/assemblies.d.ts +28 -0
  19. package/lib/api/services/assemblies.js +49 -0
  20. package/lib/api/services/beams.d.ts +33 -0
  21. package/lib/api/services/beams.js +59 -0
  22. package/lib/api/services/columns.d.ts +26 -0
  23. package/lib/api/services/columns.js +56 -0
  24. package/lib/api/services/defaults.constants.d.ts +44 -0
  25. package/lib/api/services/defaults.constants.js +44 -0
  26. package/lib/api/services/doors.d.ts +45 -0
  27. package/lib/api/services/doors.js +94 -0
  28. package/lib/api/services/geometry.d.ts +51 -0
  29. package/lib/api/services/geometry.js +87 -0
  30. package/lib/api/services/index.d.ts +17 -0
  31. package/lib/api/services/index.js +17 -0
  32. package/lib/api/services/materials.d.ts +46 -0
  33. package/lib/api/services/materials.js +86 -0
  34. package/lib/api/services/member-support.d.ts +7 -0
  35. package/lib/api/services/member-support.js +29 -0
  36. package/lib/api/services/members.d.ts +24 -0
  37. package/lib/api/services/members.js +51 -0
  38. package/lib/api/services/model.d.ts +244 -0
  39. package/lib/api/services/model.js +409 -0
  40. package/lib/api/services/openings.d.ts +57 -0
  41. package/lib/api/services/openings.js +102 -0
  42. package/lib/api/services/properties.d.ts +89 -0
  43. package/lib/api/services/properties.js +142 -0
  44. package/lib/api/services/quantities.d.ts +38 -0
  45. package/lib/api/services/quantities.js +51 -0
  46. package/lib/api/services/roofs.d.ts +24 -0
  47. package/lib/api/services/roofs.js +52 -0
  48. package/lib/api/services/service-support.d.ts +8 -0
  49. package/lib/api/services/service-support.js +37 -0
  50. package/lib/api/services/service-types.d.ts +3 -0
  51. package/lib/api/services/service-types.js +1 -0
  52. package/lib/api/services/site.d.ts +37 -0
  53. package/lib/api/services/site.js +80 -0
  54. package/lib/api/services/slabs.d.ts +31 -0
  55. package/lib/api/services/slabs.js +59 -0
  56. package/lib/api/services/spaces.d.ts +36 -0
  57. package/lib/api/services/spaces.js +64 -0
  58. package/lib/api/services/spatial.d.ts +54 -0
  59. package/lib/api/services/spatial.js +75 -0
  60. package/lib/api/services/walls.d.ts +140 -0
  61. package/lib/api/services/walls.js +268 -0
  62. package/lib/api/services/windows.d.ts +46 -0
  63. package/lib/api/services/windows.js +76 -0
  64. package/lib/build/assemblies.d.ts +4 -0
  65. package/lib/build/assemblies.js +45 -0
  66. package/lib/build/build-types.d.ts +345 -0
  67. package/lib/build/build-types.js +1 -0
  68. package/lib/build/checks.d.ts +6 -0
  69. package/lib/build/checks.js +32 -0
  70. package/lib/build/constants.d.ts +27 -0
  71. package/lib/build/constants.js +43 -0
  72. package/lib/build/contexts.d.ts +9 -0
  73. package/lib/build/contexts.js +52 -0
  74. package/lib/build/curves.d.ts +3 -0
  75. package/lib/build/curves.js +23 -0
  76. package/lib/build/entity-writer.d.ts +23 -0
  77. package/lib/build/entity-writer.js +97 -0
  78. package/lib/build/fillings.d.ts +7 -0
  79. package/lib/build/fillings.js +182 -0
  80. package/lib/build/georeference.d.ts +5 -0
  81. package/lib/build/georeference.js +44 -0
  82. package/lib/build/materials.d.ts +18 -0
  83. package/lib/build/materials.js +166 -0
  84. package/lib/build/math.d.ts +10 -0
  85. package/lib/build/math.js +47 -0
  86. package/lib/build/measure.d.ts +9 -0
  87. package/lib/build/measure.js +195 -0
  88. package/lib/build/moving.d.ts +4 -0
  89. package/lib/build/moving.js +61 -0
  90. package/lib/build/openings.d.ts +12 -0
  91. package/lib/build/openings.js +156 -0
  92. package/lib/build/outlines.d.ts +4 -0
  93. package/lib/build/outlines.js +40 -0
  94. package/lib/build/placement.d.ts +16 -0
  95. package/lib/build/placement.js +106 -0
  96. package/lib/build/profiles.d.ts +4 -0
  97. package/lib/build/profiles.js +35 -0
  98. package/lib/build/project.d.ts +11 -0
  99. package/lib/build/project.js +134 -0
  100. package/lib/build/properties.d.ts +10 -0
  101. package/lib/build/properties.js +182 -0
  102. package/lib/build/quantities.d.ts +7 -0
  103. package/lib/build/quantities.js +262 -0
  104. package/lib/build/relationships.d.ts +9 -0
  105. package/lib/build/relationships.js +67 -0
  106. package/lib/build/removal.d.ts +3 -0
  107. package/lib/build/removal.js +106 -0
  108. package/lib/build/representations.d.ts +6 -0
  109. package/lib/build/representations.js +46 -0
  110. package/lib/build/roof-clipping.d.ts +5 -0
  111. package/lib/build/roof-clipping.js +79 -0
  112. package/lib/build/roofs.d.ts +4 -0
  113. package/lib/build/roofs.js +131 -0
  114. package/lib/build/site.d.ts +7 -0
  115. package/lib/build/site.js +112 -0
  116. package/lib/build/slab-openings.d.ts +4 -0
  117. package/lib/build/slab-openings.js +71 -0
  118. package/lib/build/slabs-columns-beams.d.ts +8 -0
  119. package/lib/build/slabs-columns-beams.js +73 -0
  120. package/lib/build/solids.d.ts +5 -0
  121. package/lib/build/solids.js +33 -0
  122. package/lib/build/spaces.d.ts +6 -0
  123. package/lib/build/spaces.js +55 -0
  124. package/lib/build/spatial.d.ts +17 -0
  125. package/lib/build/spatial.js +111 -0
  126. package/lib/build/type-objects.d.ts +4 -0
  127. package/lib/build/type-objects.js +9 -0
  128. package/lib/build/wall-edits.d.ts +5 -0
  129. package/lib/build/wall-edits.js +138 -0
  130. package/lib/build/wall-geometry.d.ts +15 -0
  131. package/lib/build/wall-geometry.js +159 -0
  132. package/lib/build/wall-parameters.d.ts +3 -0
  133. package/lib/build/wall-parameters.js +47 -0
  134. package/lib/build/walls.d.ts +12 -0
  135. package/lib/build/walls.js +238 -0
  136. package/lib/geometry/advanced.d.ts +27 -0
  137. package/lib/geometry/advanced.js +292 -0
  138. package/lib/geometry/colours.d.ts +3 -0
  139. package/lib/geometry/colours.js +109 -0
  140. package/lib/geometry/curves.d.ts +32 -0
  141. package/lib/geometry/curves.js +370 -0
  142. package/lib/geometry/edges.constants.d.ts +5 -0
  143. package/lib/geometry/edges.constants.js +5 -0
  144. package/lib/geometry/edges.d.ts +21 -0
  145. package/lib/geometry/edges.js +164 -0
  146. package/lib/geometry/elements.d.ts +3 -0
  147. package/lib/geometry/elements.js +152 -0
  148. package/lib/geometry/errors.d.ts +3 -0
  149. package/lib/geometry/errors.js +6 -0
  150. package/lib/geometry/faceted.d.ts +31 -0
  151. package/lib/geometry/faceted.js +214 -0
  152. package/lib/geometry/geometry-types.d.ts +103 -0
  153. package/lib/geometry/geometry-types.js +1 -0
  154. package/lib/geometry/groups.d.ts +21 -0
  155. package/lib/geometry/groups.js +106 -0
  156. package/lib/geometry/items.d.ts +34 -0
  157. package/lib/geometry/items.js +313 -0
  158. package/lib/geometry/operators.d.ts +3 -0
  159. package/lib/geometry/operators.js +65 -0
  160. package/lib/geometry/profiles.d.ts +4 -0
  161. package/lib/geometry/profiles.js +277 -0
  162. package/lib/geometry/recipe-builder.d.ts +14 -0
  163. package/lib/geometry/recipe-builder.js +48 -0
  164. package/lib/geometry/references.d.ts +4 -0
  165. package/lib/geometry/references.js +17 -0
  166. package/lib/geometry/regions.d.ts +4 -0
  167. package/lib/geometry/regions.js +26 -0
  168. package/lib/geometry/surfaces.constants.d.ts +17 -0
  169. package/lib/geometry/surfaces.constants.js +17 -0
  170. package/lib/geometry/surfaces.d.ts +6 -0
  171. package/lib/geometry/surfaces.js +306 -0
  172. package/lib/geometry/swept-solids.constants.d.ts +7 -0
  173. package/lib/geometry/swept-solids.constants.js +6 -0
  174. package/lib/geometry/swept-solids.d.ts +25 -0
  175. package/lib/geometry/swept-solids.js +243 -0
  176. package/lib/index.d.ts +6 -0
  177. package/lib/index.js +6 -0
  178. package/lib/model/constants.d.ts +30 -0
  179. package/lib/model/constants.js +30 -0
  180. package/lib/model/entity-lookup.d.ts +9 -0
  181. package/lib/model/entity-lookup.js +20 -0
  182. package/lib/model/guid.d.ts +7 -0
  183. package/lib/model/guid.js +60 -0
  184. package/lib/model/id-map.d.ts +10 -0
  185. package/lib/model/id-map.js +80 -0
  186. package/lib/model/index.d.ts +4 -0
  187. package/lib/model/index.js +2 -0
  188. package/lib/model/io.d.ts +6 -0
  189. package/lib/model/io.js +136 -0
  190. package/lib/model/is-model.d.ts +9 -0
  191. package/lib/model/is-model.js +11 -0
  192. package/lib/model/model-types.d.ts +111 -0
  193. package/lib/model/model-types.js +1 -0
  194. package/lib/model/overlay-indexes.d.ts +17 -0
  195. package/lib/model/overlay-indexes.js +69 -0
  196. package/lib/model/references.d.ts +2 -0
  197. package/lib/model/references.js +51 -0
  198. package/lib/model/rows-by-id.d.ts +8 -0
  199. package/lib/model/rows-by-id.js +39 -0
  200. package/lib/model/snapshot.d.ts +36 -0
  201. package/lib/model/snapshot.js +144 -0
  202. package/lib/model/source.d.ts +29 -0
  203. package/lib/model/source.js +172 -0
  204. package/lib/model/transaction.d.ts +39 -0
  205. package/lib/model/transaction.js +250 -0
  206. package/lib/model/upgrade.d.ts +2 -0
  207. package/lib/model/upgrade.js +78 -0
  208. package/lib/schema/constants.d.ts +3 -0
  209. package/lib/schema/constants.js +3 -0
  210. package/lib/schema/generated/ifc4.d.ts +2 -0
  211. package/lib/schema/generated/ifc4.js +1204 -0
  212. package/lib/schema/generated/ifc4x3.d.ts +2 -0
  213. package/lib/schema/generated/ifc4x3.js +1325 -0
  214. package/lib/schema/registry.d.ts +7 -0
  215. package/lib/schema/registry.js +37 -0
  216. package/lib/schema/schema-types.d.ts +45 -0
  217. package/lib/schema/schema-types.js +1 -0
  218. package/lib/schema/schema.d.ts +23 -0
  219. package/lib/schema/schema.js +136 -0
  220. package/lib/step/constants.d.ts +48 -0
  221. package/lib/step/constants.js +48 -0
  222. package/lib/step/encoder.d.ts +21 -0
  223. package/lib/step/encoder.js +321 -0
  224. package/lib/step/errors.d.ts +39 -0
  225. package/lib/step/errors.js +45 -0
  226. package/lib/step/file-index.d.ts +2 -0
  227. package/lib/step/file-index.js +221 -0
  228. package/lib/step/header.d.ts +4 -0
  229. package/lib/step/header.js +52 -0
  230. package/lib/step/numbers.d.ts +3 -0
  231. package/lib/step/numbers.js +73 -0
  232. package/lib/step/reader.d.ts +2 -0
  233. package/lib/step/reader.js +160 -0
  234. package/lib/step/scanner.d.ts +13 -0
  235. package/lib/step/scanner.js +203 -0
  236. package/lib/step/step-types.d.ts +170 -0
  237. package/lib/step/step-types.js +1 -0
  238. package/lib/step/strings.d.ts +2 -0
  239. package/lib/step/strings.js +150 -0
  240. package/lib/step/values.d.ts +13 -0
  241. package/lib/step/values.js +51 -0
  242. package/package.json +51 -5
@@ -0,0 +1,321 @@
1
+ import { GLOBAL_ID_PATTERN, GLOBAL_ID_TYPE } from "../schema/constants";
2
+ import { SIMPLE_TYPES } from "../schema/schema";
3
+ import { IfcValueError, ValueProblem } from "./errors";
4
+ import { formatInteger, formatReal } from "./numbers";
5
+ import { encodeString } from "./strings";
6
+ import { DERIVED, isBinary, isDerived, isEnumeration, isList, isReference, isTyped } from "./values";
7
+ const BINARY_DIGITS = /^[0-3][0-9A-Fa-f]*$/;
8
+ function describe(value) {
9
+ if (value === null) {
10
+ return "nothing";
11
+ }
12
+ if (isDerived(value)) {
13
+ return "the derived marker";
14
+ }
15
+ if (isList(value)) {
16
+ return "a list";
17
+ }
18
+ if (isReference(value)) {
19
+ return `a reference to #${value.ref}`;
20
+ }
21
+ if (isEnumeration(value)) {
22
+ return `the enumeration value ${value.enum}`;
23
+ }
24
+ if (isTyped(value)) {
25
+ return `a typed ${value.type}`;
26
+ }
27
+ if (typeof value === "string") {
28
+ return "a text";
29
+ }
30
+ return typeof value === "number" || typeof value === "boolean" ? `${typeof value} ${value}` : "an unknown value";
31
+ }
32
+ function within(error, segment) {
33
+ return error instanceof ValueProblem ? error.within(segment) : error;
34
+ }
35
+ function checkSimple(spec, value) {
36
+ switch (spec) {
37
+ case "REAL":
38
+ if (typeof value !== "number" || !Number.isFinite(value)) {
39
+ throw new ValueProblem(`expected a finite real number, got ${describe(value)}`);
40
+ }
41
+ return;
42
+ case "INTEGER":
43
+ if (typeof value !== "number" || !Number.isSafeInteger(value)) {
44
+ throw new ValueProblem(`expected a whole number, got ${describe(value)}`);
45
+ }
46
+ return;
47
+ case "NUMBER":
48
+ if (typeof value !== "number" || !Number.isFinite(value)) {
49
+ throw new ValueProblem(`expected a finite number, got ${describe(value)}`);
50
+ }
51
+ return;
52
+ case "STRING":
53
+ if (typeof value !== "string") {
54
+ throw new ValueProblem(`expected a text, got ${describe(value)}`);
55
+ }
56
+ return;
57
+ case "BOOLEAN":
58
+ if (typeof value !== "boolean") {
59
+ throw new ValueProblem(`expected true or false, got ${describe(value)}`);
60
+ }
61
+ return;
62
+ case "LOGICAL":
63
+ if (typeof value !== "boolean" && !(isEnumeration(value) && value.enum === "U")) {
64
+ throw new ValueProblem(`expected true, false or unknown, got ${describe(value)}`);
65
+ }
66
+ return;
67
+ default:
68
+ if (!isBinary(value)) {
69
+ throw new ValueProblem(`expected a binary value, got ${describe(value)}`);
70
+ }
71
+ if (!BINARY_DIGITS.test(value.binary)) {
72
+ throw new ValueProblem("a binary value is a digit from 0 to 3 followed by hexadecimal digits");
73
+ }
74
+ }
75
+ }
76
+ function formatSimple(spec, value) {
77
+ checkSimple(spec, value);
78
+ if (typeof value === "number") {
79
+ return spec === "REAL" || (spec === "NUMBER" && !Number.isSafeInteger(value)) ? formatReal(value) : formatInteger(value);
80
+ }
81
+ if (typeof value === "string") {
82
+ return encodeString(value);
83
+ }
84
+ if (typeof value === "boolean") {
85
+ return value ? ".T." : ".F.";
86
+ }
87
+ return isBinary(value) ? `"${value.binary.toUpperCase()}"` : ".U.";
88
+ }
89
+ function checkBounds(spec, value) {
90
+ const [kind, lower, upper] = spec;
91
+ if (kind === "ARRAY" && upper !== null) {
92
+ if (value.length !== upper - lower + 1) {
93
+ throw new ValueProblem(`an ARRAY [${lower}:${upper}] holds exactly ${upper - lower + 1} values, got ${value.length}`);
94
+ }
95
+ }
96
+ else if (value.length < lower || (upper !== null && value.length > upper)) {
97
+ throw new ValueProblem(`a ${kind} of ${lower} to ${upper !== null && upper !== void 0 ? upper : "any number of"} values, got ${value.length}`);
98
+ }
99
+ }
100
+ export class IfcEncoder {
101
+ constructor(schema) {
102
+ this.schema = schema;
103
+ }
104
+ normalizeArguments(type, args, path) {
105
+ const info = this.writable(type, args.length, path);
106
+ return info.attributes.map((_, index) => this.normalizeAttribute(info, index, args[index], path));
107
+ }
108
+ normalizeAttribute(info, index, value, path) {
109
+ const attribute = info.attributes[index];
110
+ try {
111
+ if (attribute.derived) {
112
+ if (value !== null && !isDerived(value)) {
113
+ throw new ValueProblem("the attribute is derived and takes no value");
114
+ }
115
+ return DERIVED;
116
+ }
117
+ if (value === null) {
118
+ if (!attribute.optional) {
119
+ throw new ValueProblem("the attribute is required");
120
+ }
121
+ return null;
122
+ }
123
+ return this.normalize(attribute.type, value);
124
+ }
125
+ catch (error) {
126
+ throw this.located(error, path, info, index);
127
+ }
128
+ }
129
+ encodeEntity(entity) {
130
+ const path = `#${entity.id}`;
131
+ const info = this.writable(entity.type, entity.args.length, path);
132
+ const parts = info.attributes.map((attribute, index) => {
133
+ const value = entity.args[index];
134
+ try {
135
+ if (attribute.derived) {
136
+ if (value !== null && !isDerived(value)) {
137
+ throw new ValueProblem("the attribute is derived and takes no value");
138
+ }
139
+ return "*";
140
+ }
141
+ if (value === null) {
142
+ if (!attribute.optional) {
143
+ throw new ValueProblem("the attribute is required");
144
+ }
145
+ return "$";
146
+ }
147
+ return this.format(attribute.type, value);
148
+ }
149
+ catch (error) {
150
+ throw this.located(error, path, info, index);
151
+ }
152
+ });
153
+ return `#${entity.id}=${info.name.toUpperCase()}(${parts.join(",")});`;
154
+ }
155
+ encodeValue(spec, value, path) {
156
+ try {
157
+ return this.format(spec, value);
158
+ }
159
+ catch (error) {
160
+ if (error instanceof ValueProblem) {
161
+ throw new IfcValueError(`${path}${error.segments.join("")}`, error.message);
162
+ }
163
+ throw error;
164
+ }
165
+ }
166
+ writable(type, count, path) {
167
+ const info = this.schema.entity(type);
168
+ if (info.abstract) {
169
+ throw new IfcValueError(path, `${info.name} is abstract and cannot be written`);
170
+ }
171
+ if (count !== info.attributes.length) {
172
+ throw new IfcValueError(path, `${info.name} has ${info.attributes.length} attributes, got ${count} values`);
173
+ }
174
+ return info;
175
+ }
176
+ located(error, path, info, index) {
177
+ if (!(error instanceof ValueProblem)) {
178
+ return error;
179
+ }
180
+ return new IfcValueError(`${path} ${info.name}.${info.attributes[index].name}${error.segments.join("")}`, error.message);
181
+ }
182
+ enumMember(spec, members, value) {
183
+ const member = typeof value === "string" ? value.toUpperCase() : isEnumeration(value) ? value.enum : undefined;
184
+ if (member === undefined || !members.includes(member)) {
185
+ throw new ValueProblem(`expected one of ${members.join(", ")} for ${spec}, got ${describe(value)}`);
186
+ }
187
+ return member;
188
+ }
189
+ selected(select, value) {
190
+ const contents = this.schema.selectContents(select);
191
+ if (isReference(value)) {
192
+ if (!contents.entities.length) {
193
+ throw new ValueProblem(`${select} takes typed values, not references`);
194
+ }
195
+ return undefined;
196
+ }
197
+ if (!isTyped(value)) {
198
+ throw new ValueProblem(`${select} needs a typed value or a reference, got ${describe(value)}`);
199
+ }
200
+ const typeName = this.schema.typeName(value.type);
201
+ if (typeName === undefined || !contents.valueTypes.has(typeName)) {
202
+ throw new ValueProblem(`${value.type} is not one of the types ${select} accepts`);
203
+ }
204
+ return { type: typeName, value: value.value };
205
+ }
206
+ definedValue(spec, value) {
207
+ if (!isTyped(value)) {
208
+ return value;
209
+ }
210
+ if (this.schema.typeName(value.type) !== this.schema.typeName(spec)) {
211
+ throw new ValueProblem(`expected ${spec}, got a typed ${value.type}`);
212
+ }
213
+ return value.value;
214
+ }
215
+ checkGlobalId(spec, value) {
216
+ if (spec === GLOBAL_ID_TYPE && (typeof value !== "string" || !GLOBAL_ID_PATTERN.test(value))) {
217
+ throw new ValueProblem("a GlobalId is 22 characters of 0-9, A-Z, a-z, _ and $, the first from 0 to 3");
218
+ }
219
+ }
220
+ normalize(spec, value) {
221
+ if (value === null || isDerived(value)) {
222
+ throw new ValueProblem(`expected a value, got ${describe(value)}`);
223
+ }
224
+ if (typeof spec !== "string") {
225
+ return this.normalizeList(spec, value);
226
+ }
227
+ if (SIMPLE_TYPES.has(spec)) {
228
+ checkSimple(spec, value);
229
+ return value;
230
+ }
231
+ if (this.schema.hasEntity(spec)) {
232
+ if (!isReference(value)) {
233
+ throw new ValueProblem(`expected a reference to an ${spec}, got ${describe(value)}`);
234
+ }
235
+ return value;
236
+ }
237
+ const type = this.schema.type(spec);
238
+ if ("e" in type) {
239
+ return { enum: this.enumMember(spec, type.e, value) };
240
+ }
241
+ if ("s" in type) {
242
+ const chosen = this.selected(spec, value);
243
+ return chosen === undefined ? value : { type: chosen.type, value: this.normalize(chosen.type, chosen.value) };
244
+ }
245
+ const inner = this.definedValue(spec, value);
246
+ this.checkGlobalId(this.schema.typeName(spec), inner);
247
+ return this.normalize(type.t, inner);
248
+ }
249
+ normalizeList(spec, value) {
250
+ if (!isList(value)) {
251
+ throw new ValueProblem(`expected a list, got ${describe(value)}`);
252
+ }
253
+ checkBounds(spec, value);
254
+ const member = spec[3];
255
+ const items = value.map((item, index) => {
256
+ try {
257
+ return this.normalize(member, item);
258
+ }
259
+ catch (error) {
260
+ throw within(error, `[${index}]`);
261
+ }
262
+ });
263
+ if (spec[0] === "SET") {
264
+ this.format(spec, items);
265
+ }
266
+ return items;
267
+ }
268
+ format(spec, value) {
269
+ if (value === null || isDerived(value)) {
270
+ throw new ValueProblem(`expected a value, got ${describe(value)}`);
271
+ }
272
+ if (typeof spec !== "string") {
273
+ if (!isList(value)) {
274
+ throw new ValueProblem(`expected a list, got ${describe(value)}`);
275
+ }
276
+ checkBounds(spec, value);
277
+ const parts = value.map((item, index) => {
278
+ try {
279
+ return this.format(spec[3], item);
280
+ }
281
+ catch (error) {
282
+ throw within(error, `[${index}]`);
283
+ }
284
+ });
285
+ if (spec[0] === "SET" && new Set(parts).size !== parts.length) {
286
+ throw new ValueProblem("a SET holds each value once, and this one repeats a value");
287
+ }
288
+ return `(${parts.join(",")})`;
289
+ }
290
+ if (SIMPLE_TYPES.has(spec)) {
291
+ return formatSimple(spec, value);
292
+ }
293
+ if (this.schema.hasEntity(spec)) {
294
+ if (!isReference(value)) {
295
+ throw new ValueProblem(`expected a reference to an ${spec}, got ${describe(value)}`);
296
+ }
297
+ return `#${value.ref}`;
298
+ }
299
+ const type = this.schema.type(spec);
300
+ if (!type) {
301
+ throw new ValueProblem(`the schema has no type ${spec}`);
302
+ }
303
+ if ("e" in type) {
304
+ return `.${this.enumMember(spec, type.e, value)}.`;
305
+ }
306
+ if ("s" in type) {
307
+ const chosen = this.selected(spec, value);
308
+ return chosen === undefined ? this.format(this.schema.selectContents(spec).entities[0], value) : `${chosen.type.toUpperCase()}(${this.format(chosen.type, chosen.value)})`;
309
+ }
310
+ return this.format(type.t, this.definedValue(spec, value));
311
+ }
312
+ }
313
+ const encoders = new WeakMap();
314
+ export function encoderFor(schema) {
315
+ let encoder = encoders.get(schema);
316
+ if (!encoder) {
317
+ encoder = new IfcEncoder(schema);
318
+ encoders.set(schema, encoder);
319
+ }
320
+ return encoder;
321
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * A file that does not follow the ISO 10303-21 encoding, holds an entity id twice, names a schema
3
+ * this library does not read or an entity type its schema does not define, with the byte where the
4
+ * problem is. A row is decoded when it is first asked for, so a broken row raises it then.
5
+ * @beta
6
+ */
7
+ export declare class StepSyntaxError extends Error {
8
+ /**
9
+ * The offset of the byte at which the problem was found.
10
+ */
11
+ readonly offset: number;
12
+ /**
13
+ * Makes the error.
14
+ * @param message - What is wrong
15
+ * @param offset - The offset of the byte at which the problem was found
16
+ */
17
+ constructor(message: string, offset: number);
18
+ }
19
+ /**
20
+ * An attribute value that its schema type does not accept, with the entity and attribute it was
21
+ * given for.
22
+ * @beta
23
+ */
24
+ export declare class IfcValueError extends Error {
25
+ /**
26
+ * Where the value was given, such as `#12 IfcWall.Name` or `#12 IfcPolyline.Points[3]`.
27
+ */
28
+ readonly path: string;
29
+ /**
30
+ * Makes the error.
31
+ * @param path - Where the value was given
32
+ * @param message - What is wrong with it
33
+ */
34
+ constructor(path: string, message: string);
35
+ }
36
+ export declare class ValueProblem extends Error {
37
+ readonly segments: string[];
38
+ within(segment: string): ValueProblem;
39
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * A file that does not follow the ISO 10303-21 encoding, holds an entity id twice, names a schema
3
+ * this library does not read or an entity type its schema does not define, with the byte where the
4
+ * problem is. A row is decoded when it is first asked for, so a broken row raises it then.
5
+ * @beta
6
+ */
7
+ export class StepSyntaxError extends Error {
8
+ /**
9
+ * Makes the error.
10
+ * @param message - What is wrong
11
+ * @param offset - The offset of the byte at which the problem was found
12
+ */
13
+ constructor(message, offset) {
14
+ super(`${message} at byte ${offset}`);
15
+ this.name = "StepSyntaxError";
16
+ this.offset = offset;
17
+ }
18
+ }
19
+ /**
20
+ * An attribute value that its schema type does not accept, with the entity and attribute it was
21
+ * given for.
22
+ * @beta
23
+ */
24
+ export class IfcValueError extends Error {
25
+ /**
26
+ * Makes the error.
27
+ * @param path - Where the value was given
28
+ * @param message - What is wrong with it
29
+ */
30
+ constructor(path, message) {
31
+ super(`${path}: ${message}`);
32
+ this.name = "IfcValueError";
33
+ this.path = path;
34
+ }
35
+ }
36
+ export class ValueProblem extends Error {
37
+ constructor() {
38
+ super(...arguments);
39
+ this.segments = [];
40
+ }
41
+ within(segment) {
42
+ this.segments.unshift(segment);
43
+ return this;
44
+ }
45
+ }
@@ -0,0 +1,2 @@
1
+ import type { StepIndex } from "./step-types";
2
+ export declare function indexStep(bytes: Uint8Array): StepIndex;
@@ -0,0 +1,221 @@
1
+ import { BOM, CHAR_EQUALS, CHAR_HASH, CHAR_LOWER_A, CHAR_LOWER_Z, CHAR_MINUS, CHAR_OPEN, CHAR_SEMICOLON, CHAR_ZERO, DECIMAL_RADIX, INITIAL_ROWS, MAX_EXPRESS_ID, MAX_FILE_BYTES, MAX_TYPE_CODES, TYPE_HASH_PRIME, UPPER_CASE_OFFSET, } from "./constants";
2
+ import { StepSyntaxError } from "./errors";
3
+ import { decodeArguments } from "./reader";
4
+ import { closingParenthesis, isDigit, isNameCharacter, skipSpace, textOf } from "./scanner";
5
+ function grown(array, make) {
6
+ const next = make(array.length * 2);
7
+ next.set(array);
8
+ return next;
9
+ }
10
+ function upperCased(code) {
11
+ return code >= CHAR_LOWER_A && code <= CHAR_LOWER_Z ? code - UPPER_CASE_OFFSET : code;
12
+ }
13
+ function spells(name, bytes, start, end) {
14
+ if (name.length !== end - start) {
15
+ return false;
16
+ }
17
+ for (let at = start; at < end; at++) {
18
+ if (name.charCodeAt(at - start) !== upperCased(bytes[at])) {
19
+ return false;
20
+ }
21
+ }
22
+ return true;
23
+ }
24
+ function typeCodeOf(rows, bytes, start, end) {
25
+ let hash = end - start;
26
+ for (let at = start; at < end; at++) {
27
+ hash = Math.imul(hash ^ upperCased(bytes[at]), TYPE_HASH_PRIME);
28
+ }
29
+ const candidates = rows.codesOfHash.get(hash);
30
+ for (const code of candidates !== null && candidates !== void 0 ? candidates : []) {
31
+ if (spells(rows.typeTable[code], bytes, start, end)) {
32
+ return code;
33
+ }
34
+ }
35
+ if (rows.typeTable.length === MAX_TYPE_CODES) {
36
+ throw new StepSyntaxError(`The file names more than ${MAX_TYPE_CODES} entity types`, start);
37
+ }
38
+ let name = "";
39
+ for (let at = start; at < end; at++) {
40
+ name += String.fromCharCode(upperCased(bytes[at]));
41
+ }
42
+ const code = rows.typeTable.push(name) - 1;
43
+ if (candidates) {
44
+ candidates.push(code);
45
+ }
46
+ else {
47
+ rows.codesOfHash.set(hash, [code]);
48
+ }
49
+ return code;
50
+ }
51
+ function addRow(rows, id, typeCode, spans) {
52
+ if (rows.count === rows.ids.length) {
53
+ rows.ids = grown(rows.ids, (n) => new Int32Array(n));
54
+ rows.typeCodes = grown(rows.typeCodes, (n) => new Uint16Array(n));
55
+ rows.argStart = grown(rows.argStart, (n) => new Uint32Array(n));
56
+ rows.argEnd = grown(rows.argEnd, (n) => new Uint32Array(n));
57
+ rows.rowStart = grown(rows.rowStart, (n) => new Uint32Array(n));
58
+ rows.rowEnd = grown(rows.rowEnd, (n) => new Uint32Array(n));
59
+ }
60
+ rows.ids[rows.count] = id;
61
+ rows.typeCodes[rows.count] = typeCode;
62
+ rows.rowStart[rows.count] = spans.rowStart;
63
+ rows.argStart[rows.count] = spans.argStart;
64
+ rows.argEnd[rows.count] = spans.argEnd;
65
+ rows.rowEnd[rows.count] = spans.rowEnd;
66
+ rows.count++;
67
+ }
68
+ function readKeyword(bytes, at) {
69
+ let end = at;
70
+ while (end < bytes.length && (isNameCharacter(bytes[end]) || bytes[end] === CHAR_MINUS)) {
71
+ end++;
72
+ }
73
+ return [textOf(bytes, at, end).toUpperCase(), end];
74
+ }
75
+ function expectSemicolon(bytes, at, after) {
76
+ const position = skipSpace(bytes, at, bytes.length);
77
+ if (bytes[position] !== CHAR_SEMICOLON) {
78
+ throw new StepSyntaxError(`Expected ';' after ${after}`, position);
79
+ }
80
+ return position + 1;
81
+ }
82
+ function expectKeyword(bytes, at, keyword) {
83
+ const position = skipSpace(bytes, at, bytes.length);
84
+ const [found, end] = readKeyword(bytes, position);
85
+ if (found !== keyword) {
86
+ throw new StepSyntaxError(`Expected ${keyword}`, position);
87
+ }
88
+ return end;
89
+ }
90
+ function readHeader(bytes, from) {
91
+ const header = [];
92
+ let at = expectSemicolon(bytes, expectKeyword(bytes, from, "HEADER"), "HEADER");
93
+ for (;;) {
94
+ at = skipSpace(bytes, at, bytes.length);
95
+ const [name, nameEnd] = readKeyword(bytes, at);
96
+ if (name === "ENDSEC") {
97
+ return [header, expectSemicolon(bytes, nameEnd, "ENDSEC"), at];
98
+ }
99
+ if (!name) {
100
+ throw new StepSyntaxError("Expected a header entity or ENDSEC", at);
101
+ }
102
+ const open = skipSpace(bytes, nameEnd, bytes.length);
103
+ if (bytes[open] !== CHAR_OPEN) {
104
+ throw new StepSyntaxError(`The header entity ${name} has no attribute list`, open);
105
+ }
106
+ const close = closingParenthesis(bytes, open, bytes.length);
107
+ const end = expectSemicolon(bytes, close + 1, name);
108
+ header.push({ type: name, args: decodeArguments(bytes, open + 1, close), text: textOf(bytes, at, end), offset: at });
109
+ at = end;
110
+ }
111
+ }
112
+ function readRow(bytes, at, rows) {
113
+ let idEnd = at + 1;
114
+ let id = 0;
115
+ while (idEnd < bytes.length && isDigit(bytes[idEnd])) {
116
+ id = id * DECIMAL_RADIX + bytes[idEnd] - CHAR_ZERO;
117
+ idEnd++;
118
+ }
119
+ if (idEnd === at + 1) {
120
+ throw new StepSyntaxError("An entity without an id", at);
121
+ }
122
+ if (id > MAX_EXPRESS_ID) {
123
+ throw new StepSyntaxError(`Entity #${textOf(bytes, at + 1, idEnd)} has an id above ${MAX_EXPRESS_ID}, which this library does not read`, at);
124
+ }
125
+ const equals = skipSpace(bytes, idEnd, bytes.length);
126
+ if (bytes[equals] !== CHAR_EQUALS) {
127
+ throw new StepSyntaxError(`Entity #${id} has no '='`, equals);
128
+ }
129
+ const nameStart = skipSpace(bytes, equals + 1, bytes.length);
130
+ let nameEnd = nameStart;
131
+ while (nameEnd < bytes.length && isNameCharacter(bytes[nameEnd])) {
132
+ nameEnd++;
133
+ }
134
+ const open = skipSpace(bytes, nameEnd, bytes.length);
135
+ if (bytes[open] !== CHAR_OPEN) {
136
+ throw new StepSyntaxError(`Entity #${id} has no attribute list`, open);
137
+ }
138
+ const close = closingParenthesis(bytes, open, bytes.length);
139
+ const semicolon = skipSpace(bytes, close + 1, bytes.length);
140
+ if (bytes[semicolon] !== CHAR_SEMICOLON) {
141
+ throw new StepSyntaxError(`Entity #${id} does not end with ';'`, semicolon);
142
+ }
143
+ const rowEnd = semicolon + 1;
144
+ addRow(rows, id, typeCodeOf(rows, bytes, nameStart, nameEnd), { rowStart: at, argStart: open + 1, argEnd: close, rowEnd });
145
+ return rowEnd;
146
+ }
147
+ function readDataSection(bytes, from, rows) {
148
+ let at = skipSpace(bytes, from, bytes.length);
149
+ if (bytes[at] === CHAR_OPEN) {
150
+ at = closingParenthesis(bytes, at, bytes.length) + 1;
151
+ }
152
+ at = expectSemicolon(bytes, at, "DATA");
153
+ for (;;) {
154
+ at = skipSpace(bytes, at, bytes.length);
155
+ if (at >= bytes.length) {
156
+ throw new StepSyntaxError("The DATA section never ends", at);
157
+ }
158
+ if (bytes[at] !== CHAR_HASH) {
159
+ const [keyword, keywordEnd] = readKeyword(bytes, at);
160
+ if (keyword !== "ENDSEC") {
161
+ throw new StepSyntaxError("Expected an entity or ENDSEC", at);
162
+ }
163
+ return expectSemicolon(bytes, keywordEnd, "ENDSEC");
164
+ }
165
+ at = readRow(bytes, at, rows);
166
+ }
167
+ }
168
+ function startOf(bytes) {
169
+ return BOM.every((byte, index) => bytes[index] === byte) ? BOM.length : 0;
170
+ }
171
+ export function indexStep(bytes) {
172
+ if (bytes.length > MAX_FILE_BYTES) {
173
+ throw new StepSyntaxError(`The file holds ${bytes.length} bytes; files of 4 GiB or more are not read`, 0);
174
+ }
175
+ const [header, afterHeader, headerEnd] = readHeader(bytes, expectSemicolon(bytes, expectKeyword(bytes, startOf(bytes), "ISO-10303-21"), "ISO-10303-21"));
176
+ const rows = {
177
+ count: 0,
178
+ ids: new Int32Array(INITIAL_ROWS),
179
+ typeCodes: new Uint16Array(INITIAL_ROWS),
180
+ typeTable: [],
181
+ codesOfHash: new Map(),
182
+ argStart: new Uint32Array(INITIAL_ROWS),
183
+ argEnd: new Uint32Array(INITIAL_ROWS),
184
+ rowStart: new Uint32Array(INITIAL_ROWS),
185
+ rowEnd: new Uint32Array(INITIAL_ROWS),
186
+ };
187
+ const sectionStarts = [];
188
+ let at = readDataSection(bytes, expectKeyword(bytes, afterHeader, "DATA"), rows);
189
+ for (;;) {
190
+ at = skipSpace(bytes, at, bytes.length);
191
+ const [keyword, keywordEnd] = readKeyword(bytes, at);
192
+ if (keyword === "DATA") {
193
+ sectionStarts.push(rows.count);
194
+ at = readDataSection(bytes, keywordEnd, rows);
195
+ continue;
196
+ }
197
+ if (keyword !== "END-ISO-10303-21") {
198
+ throw new StepSyntaxError("Expected DATA or END-ISO-10303-21", at);
199
+ }
200
+ const end = skipSpace(bytes, expectSemicolon(bytes, keywordEnd, "END-ISO-10303-21"), bytes.length);
201
+ if (end < bytes.length) {
202
+ throw new StepSyntaxError("The file goes on after END-ISO-10303-21;", end);
203
+ }
204
+ break;
205
+ }
206
+ return {
207
+ bytes,
208
+ count: rows.count,
209
+ ids: rows.ids.subarray(0, rows.count),
210
+ typeCodes: rows.typeCodes.subarray(0, rows.count),
211
+ typeTable: rows.typeTable,
212
+ argStart: rows.argStart.subarray(0, rows.count),
213
+ argEnd: rows.argEnd.subarray(0, rows.count),
214
+ rowStart: rows.rowStart.subarray(0, rows.count),
215
+ rowEnd: rows.rowEnd.subarray(0, rows.count),
216
+ header,
217
+ headerEnd,
218
+ afterHeader,
219
+ sectionStarts,
220
+ };
221
+ }
@@ -0,0 +1,4 @@
1
+ import type { IfcFileHeader, StepHeaderEntity } from "./step-types";
2
+ export declare function headerFromEntities(entities: readonly StepHeaderEntity[]): IfcFileHeader;
3
+ export declare function otherHeaderEntities(entities: readonly StepHeaderEntity[]): string[];
4
+ export declare function encodeHeader(header: IfcFileHeader, others?: readonly string[]): string;
@@ -0,0 +1,52 @@
1
+ import { DEFAULT_IMPLEMENTATION_LEVEL, HEADER_ENTITIES_READ } from "./constants";
2
+ import { encodeString } from "./strings";
3
+ const READ = new Set(HEADER_ENTITIES_READ);
4
+ function texts(value) {
5
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
6
+ }
7
+ function text(value) {
8
+ return typeof value === "string" ? value : "";
9
+ }
10
+ export function headerFromEntities(entities) {
11
+ const find = (type) => { var _a, _b; return (_b = (_a = entities.find((entity) => entity.type === type)) === null || _a === void 0 ? void 0 : _a.args) !== null && _b !== void 0 ? _b : []; };
12
+ const description = find("FILE_DESCRIPTION");
13
+ const name = find("FILE_NAME");
14
+ const schema = find("FILE_SCHEMA");
15
+ return {
16
+ description: texts(description[0]),
17
+ implementationLevel: text(description[1]) || DEFAULT_IMPLEMENTATION_LEVEL,
18
+ name: text(name[0]),
19
+ timeStamp: text(name[1]),
20
+ author: texts(name[2]),
21
+ organization: texts(name[3]),
22
+ preprocessorVersion: text(name[4]),
23
+ originatingSystem: text(name[5]),
24
+ authorization: text(name[6]),
25
+ schemaIdentifiers: texts(schema[0]),
26
+ };
27
+ }
28
+ export function otherHeaderEntities(entities) {
29
+ return entities.filter((entity) => !READ.has(entity.type)).map((entity) => entity.text);
30
+ }
31
+ function list(values) {
32
+ return `(${(values.length ? values : [""]).map(encodeString).join(",")})`;
33
+ }
34
+ export function encodeHeader(header, others = []) {
35
+ return [
36
+ "ISO-10303-21;",
37
+ "HEADER;",
38
+ `FILE_DESCRIPTION(${list(header.description)},${encodeString(header.implementationLevel)});`,
39
+ `FILE_NAME(${[
40
+ encodeString(header.name),
41
+ encodeString(header.timeStamp),
42
+ list(header.author),
43
+ list(header.organization),
44
+ encodeString(header.preprocessorVersion),
45
+ encodeString(header.originatingSystem),
46
+ encodeString(header.authorization),
47
+ ].join(",")});`,
48
+ `FILE_SCHEMA(${list(header.schemaIdentifiers)});`,
49
+ ...others,
50
+ "ENDSEC;",
51
+ ].join("\n");
52
+ }
@@ -0,0 +1,3 @@
1
+ export declare function formatReal(value: number): string;
2
+ export declare function formatInteger(value: number): string;
3
+ export declare function exactDecimal(bytes: Uint8Array, start: number, end: number): number | undefined;