@itwin/core-backend 5.2.0-dev.3 → 5.2.0-dev.31

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 (193) hide show
  1. package/CHANGELOG.md +79 -1
  2. package/lib/cjs/BackendHubAccess.d.ts +2 -0
  3. package/lib/cjs/BackendHubAccess.d.ts.map +1 -1
  4. package/lib/cjs/BackendHubAccess.js.map +1 -1
  5. package/lib/cjs/BackendLoggerCategory.d.ts +6 -0
  6. package/lib/cjs/BackendLoggerCategory.d.ts.map +1 -1
  7. package/lib/cjs/BackendLoggerCategory.js +6 -0
  8. package/lib/cjs/BackendLoggerCategory.js.map +1 -1
  9. package/lib/cjs/BriefcaseManager.d.ts +57 -3
  10. package/lib/cjs/BriefcaseManager.d.ts.map +1 -1
  11. package/lib/cjs/BriefcaseManager.js +153 -44
  12. package/lib/cjs/BriefcaseManager.js.map +1 -1
  13. package/lib/cjs/ClassRegistry.js +2 -2
  14. package/lib/cjs/ClassRegistry.js.map +1 -1
  15. package/lib/cjs/CloudSqlite.d.ts +4 -0
  16. package/lib/cjs/CloudSqlite.d.ts.map +1 -1
  17. package/lib/cjs/CloudSqlite.js.map +1 -1
  18. package/lib/cjs/ECDb.d.ts +8 -0
  19. package/lib/cjs/ECDb.d.ts.map +1 -1
  20. package/lib/cjs/ECDb.js +22 -0
  21. package/lib/cjs/ECDb.js.map +1 -1
  22. package/lib/cjs/IModelDb.d.ts +54 -3
  23. package/lib/cjs/IModelDb.d.ts.map +1 -1
  24. package/lib/cjs/IModelDb.js +88 -10
  25. package/lib/cjs/IModelDb.js.map +1 -1
  26. package/lib/cjs/IModelHost.d.ts +11 -1
  27. package/lib/cjs/IModelHost.d.ts.map +1 -1
  28. package/lib/cjs/IModelHost.js +5 -0
  29. package/lib/cjs/IModelHost.js.map +1 -1
  30. package/lib/cjs/IModelIncrementalSchemaLocater.d.ts +1 -5
  31. package/lib/cjs/IModelIncrementalSchemaLocater.d.ts.map +1 -1
  32. package/lib/cjs/IModelIncrementalSchemaLocater.js +0 -6
  33. package/lib/cjs/IModelIncrementalSchemaLocater.js.map +1 -1
  34. package/lib/cjs/StashManager.d.ts +175 -0
  35. package/lib/cjs/StashManager.d.ts.map +1 -0
  36. package/lib/cjs/StashManager.js +306 -0
  37. package/lib/cjs/StashManager.js.map +1 -0
  38. package/lib/cjs/TxnManager.d.ts +226 -15
  39. package/lib/cjs/TxnManager.d.ts.map +1 -1
  40. package/lib/cjs/TxnManager.js +249 -23
  41. package/lib/cjs/TxnManager.js.map +1 -1
  42. package/lib/cjs/annotations/ElementDrivesTextAnnotation.d.ts +10 -1
  43. package/lib/cjs/annotations/ElementDrivesTextAnnotation.d.ts.map +1 -1
  44. package/lib/cjs/annotations/ElementDrivesTextAnnotation.js +12 -1
  45. package/lib/cjs/annotations/ElementDrivesTextAnnotation.js.map +1 -1
  46. package/lib/cjs/annotations/LeaderGeometry.d.ts +3 -2
  47. package/lib/cjs/annotations/LeaderGeometry.d.ts.map +1 -1
  48. package/lib/cjs/annotations/LeaderGeometry.js +4 -3
  49. package/lib/cjs/annotations/LeaderGeometry.js.map +1 -1
  50. package/lib/cjs/annotations/TextAnnotationElement.d.ts +52 -24
  51. package/lib/cjs/annotations/TextAnnotationElement.d.ts.map +1 -1
  52. package/lib/cjs/annotations/TextAnnotationElement.js +49 -59
  53. package/lib/cjs/annotations/TextAnnotationElement.js.map +1 -1
  54. package/lib/cjs/annotations/TextAnnotationGeometry.d.ts +2 -0
  55. package/lib/cjs/annotations/TextAnnotationGeometry.d.ts.map +1 -1
  56. package/lib/cjs/annotations/TextAnnotationGeometry.js +2 -2
  57. package/lib/cjs/annotations/TextAnnotationGeometry.js.map +1 -1
  58. package/lib/cjs/annotations/TextBlockLayout.d.ts +3 -9
  59. package/lib/cjs/annotations/TextBlockLayout.d.ts.map +1 -1
  60. package/lib/cjs/annotations/TextBlockLayout.js +3 -22
  61. package/lib/cjs/annotations/TextBlockLayout.js.map +1 -1
  62. package/lib/cjs/internal/ChannelAdmin.js +1 -1
  63. package/lib/cjs/internal/ChannelAdmin.js.map +1 -1
  64. package/lib/cjs/internal/Symbols.d.ts +1 -0
  65. package/lib/cjs/internal/Symbols.d.ts.map +1 -1
  66. package/lib/cjs/internal/Symbols.js +2 -1
  67. package/lib/cjs/internal/Symbols.js.map +1 -1
  68. package/lib/cjs/internal/annotations/fields.d.ts +2 -12
  69. package/lib/cjs/internal/annotations/fields.d.ts.map +1 -1
  70. package/lib/cjs/internal/annotations/fields.js +47 -40
  71. package/lib/cjs/internal/annotations/fields.js.map +1 -1
  72. package/lib/cjs/internal/workspace/SettingsImpl.js +1 -1
  73. package/lib/cjs/internal/workspace/SettingsImpl.js.map +1 -1
  74. package/lib/cjs/internal/workspace/SettingsSchemasImpl.js +2 -2
  75. package/lib/cjs/internal/workspace/SettingsSchemasImpl.js.map +1 -1
  76. package/lib/cjs/workspace/Workspace.d.ts +1 -1
  77. package/lib/cjs/workspace/Workspace.js.map +1 -1
  78. package/lib/esm/BackendHubAccess.d.ts +2 -0
  79. package/lib/esm/BackendHubAccess.d.ts.map +1 -1
  80. package/lib/esm/BackendHubAccess.js.map +1 -1
  81. package/lib/esm/BackendLoggerCategory.d.ts +6 -0
  82. package/lib/esm/BackendLoggerCategory.d.ts.map +1 -1
  83. package/lib/esm/BackendLoggerCategory.js +6 -0
  84. package/lib/esm/BackendLoggerCategory.js.map +1 -1
  85. package/lib/esm/BriefcaseManager.d.ts +57 -3
  86. package/lib/esm/BriefcaseManager.d.ts.map +1 -1
  87. package/lib/esm/BriefcaseManager.js +154 -45
  88. package/lib/esm/BriefcaseManager.js.map +1 -1
  89. package/lib/esm/ClassRegistry.js +2 -2
  90. package/lib/esm/ClassRegistry.js.map +1 -1
  91. package/lib/esm/CloudSqlite.d.ts +4 -0
  92. package/lib/esm/CloudSqlite.d.ts.map +1 -1
  93. package/lib/esm/CloudSqlite.js.map +1 -1
  94. package/lib/esm/ECDb.d.ts +8 -0
  95. package/lib/esm/ECDb.d.ts.map +1 -1
  96. package/lib/esm/ECDb.js +22 -0
  97. package/lib/esm/ECDb.js.map +1 -1
  98. package/lib/esm/IModelDb.d.ts +54 -3
  99. package/lib/esm/IModelDb.d.ts.map +1 -1
  100. package/lib/esm/IModelDb.js +89 -11
  101. package/lib/esm/IModelDb.js.map +1 -1
  102. package/lib/esm/IModelHost.d.ts +11 -1
  103. package/lib/esm/IModelHost.d.ts.map +1 -1
  104. package/lib/esm/IModelHost.js +5 -0
  105. package/lib/esm/IModelHost.js.map +1 -1
  106. package/lib/esm/IModelIncrementalSchemaLocater.d.ts +1 -5
  107. package/lib/esm/IModelIncrementalSchemaLocater.d.ts.map +1 -1
  108. package/lib/esm/IModelIncrementalSchemaLocater.js +0 -6
  109. package/lib/esm/IModelIncrementalSchemaLocater.js.map +1 -1
  110. package/lib/esm/StashManager.d.ts +175 -0
  111. package/lib/esm/StashManager.d.ts.map +1 -0
  112. package/lib/esm/StashManager.js +301 -0
  113. package/lib/esm/StashManager.js.map +1 -0
  114. package/lib/esm/TxnManager.d.ts +226 -15
  115. package/lib/esm/TxnManager.d.ts.map +1 -1
  116. package/lib/esm/TxnManager.js +247 -21
  117. package/lib/esm/TxnManager.js.map +1 -1
  118. package/lib/esm/annotations/ElementDrivesTextAnnotation.d.ts +10 -1
  119. package/lib/esm/annotations/ElementDrivesTextAnnotation.d.ts.map +1 -1
  120. package/lib/esm/annotations/ElementDrivesTextAnnotation.js +10 -0
  121. package/lib/esm/annotations/ElementDrivesTextAnnotation.js.map +1 -1
  122. package/lib/esm/annotations/LeaderGeometry.d.ts +3 -2
  123. package/lib/esm/annotations/LeaderGeometry.d.ts.map +1 -1
  124. package/lib/esm/annotations/LeaderGeometry.js +4 -3
  125. package/lib/esm/annotations/LeaderGeometry.js.map +1 -1
  126. package/lib/esm/annotations/TextAnnotationElement.d.ts +52 -24
  127. package/lib/esm/annotations/TextAnnotationElement.d.ts.map +1 -1
  128. package/lib/esm/annotations/TextAnnotationElement.js +51 -61
  129. package/lib/esm/annotations/TextAnnotationElement.js.map +1 -1
  130. package/lib/esm/annotations/TextAnnotationGeometry.d.ts +2 -0
  131. package/lib/esm/annotations/TextAnnotationGeometry.d.ts.map +1 -1
  132. package/lib/esm/annotations/TextAnnotationGeometry.js +2 -2
  133. package/lib/esm/annotations/TextAnnotationGeometry.js.map +1 -1
  134. package/lib/esm/annotations/TextBlockLayout.d.ts +3 -9
  135. package/lib/esm/annotations/TextBlockLayout.d.ts.map +1 -1
  136. package/lib/esm/annotations/TextBlockLayout.js +3 -22
  137. package/lib/esm/annotations/TextBlockLayout.js.map +1 -1
  138. package/lib/esm/internal/ChannelAdmin.js +1 -1
  139. package/lib/esm/internal/ChannelAdmin.js.map +1 -1
  140. package/lib/esm/internal/Symbols.d.ts +1 -0
  141. package/lib/esm/internal/Symbols.d.ts.map +1 -1
  142. package/lib/esm/internal/Symbols.js +1 -0
  143. package/lib/esm/internal/Symbols.js.map +1 -1
  144. package/lib/esm/internal/annotations/fields.d.ts +2 -12
  145. package/lib/esm/internal/annotations/fields.d.ts.map +1 -1
  146. package/lib/esm/internal/annotations/fields.js +50 -43
  147. package/lib/esm/internal/annotations/fields.js.map +1 -1
  148. package/lib/esm/internal/workspace/SettingsImpl.js +1 -1
  149. package/lib/esm/internal/workspace/SettingsImpl.js.map +1 -1
  150. package/lib/esm/internal/workspace/SettingsSchemasImpl.js +2 -2
  151. package/lib/esm/internal/workspace/SettingsSchemasImpl.js.map +1 -1
  152. package/lib/esm/test/AnnotationTestUtils.d.ts +5 -1
  153. package/lib/esm/test/AnnotationTestUtils.d.ts.map +1 -1
  154. package/lib/esm/test/AnnotationTestUtils.js +6 -1
  155. package/lib/esm/test/AnnotationTestUtils.js.map +1 -1
  156. package/lib/esm/test/annotations/Fields.test.js +158 -43
  157. package/lib/esm/test/annotations/Fields.test.js.map +1 -1
  158. package/lib/esm/test/annotations/LeaderGeometry.test.js +12 -10
  159. package/lib/esm/test/annotations/LeaderGeometry.test.js.map +1 -1
  160. package/lib/esm/test/annotations/TextAnnotation.test.js +299 -43
  161. package/lib/esm/test/annotations/TextAnnotation.test.js.map +1 -1
  162. package/lib/esm/test/annotations/TextBlock.test.js +39 -35
  163. package/lib/esm/test/annotations/TextBlock.test.js.map +1 -1
  164. package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.d.ts +46 -0
  165. package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.d.ts.map +1 -1
  166. package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.js +20 -2
  167. package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.js.map +1 -1
  168. package/lib/esm/test/ecdb/ECDb.test.js +71 -1
  169. package/lib/esm/test/ecdb/ECDb.test.js.map +1 -1
  170. package/lib/esm/test/ecsql/dataset/ECSqlDatasets.d.ts.map +1 -1
  171. package/lib/esm/test/ecsql/dataset/ECSqlDatasets.js +8 -2
  172. package/lib/esm/test/ecsql/dataset/ECSqlDatasets.js.map +1 -1
  173. package/lib/esm/test/hubaccess/Rebase.test.d.ts +2 -0
  174. package/lib/esm/test/hubaccess/Rebase.test.d.ts.map +1 -0
  175. package/lib/esm/test/hubaccess/Rebase.test.js +640 -0
  176. package/lib/esm/test/hubaccess/Rebase.test.js.map +1 -0
  177. package/lib/esm/test/incrementalSchemaLocater/ECSqlQueries.test.js +20 -20
  178. package/lib/esm/test/incrementalSchemaLocater/ECSqlQueries.test.js.map +1 -1
  179. package/lib/esm/test/incrementalSchemaLocater/IncrementalLoading.test.js +3 -3
  180. package/lib/esm/test/incrementalSchemaLocater/IncrementalLoading.test.js.map +1 -1
  181. package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.d.ts +16 -1
  182. package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.d.ts.map +1 -1
  183. package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.js +47 -0
  184. package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.js.map +1 -1
  185. package/lib/esm/test/standalone/ChangeMerge.test.js +15 -19
  186. package/lib/esm/test/standalone/ChangeMerge.test.js.map +1 -1
  187. package/lib/esm/test/standalone/MergeConflict.test.js +3 -3
  188. package/lib/esm/test/standalone/MergeConflict.test.js.map +1 -1
  189. package/lib/esm/test/standalone/NativeAppStorage.test.js +2 -2
  190. package/lib/esm/test/standalone/NativeAppStorage.test.js.map +1 -1
  191. package/lib/esm/workspace/Workspace.d.ts +1 -1
  192. package/lib/esm/workspace/Workspace.js.map +1 -1
  193. package/package.json +14 -14
@@ -7,14 +7,20 @@ import { Code, FieldRun, SubCategoryAppearance, TextAnnotation, TextBlock, TextR
7
7
  import { StandaloneDb } from "../../IModelDb";
8
8
  import { IModelTestUtils } from "../IModelTestUtils";
9
9
  import { createUpdateContext, updateField, updateFields } from "../../internal/annotations/fields";
10
- import { DbResult, Id64 } from "@itwin/core-bentley";
10
+ import { DbResult, Id64, ProcessDetector } from "@itwin/core-bentley";
11
11
  import { SpatialCategory } from "../../Category";
12
12
  import { Point3d, YawPitchRollAngles } from "@itwin/core-geometry";
13
13
  import { Schema, Schemas } from "../../Schema";
14
14
  import { ClassRegistry } from "../../ClassRegistry";
15
15
  import { PhysicalElement } from "../../Element";
16
16
  import { ElementOwnsUniqueAspect, ElementUniqueAspect, FontFile, TextAnnotation3d } from "../../core-backend";
17
- import { ElementDrivesTextAnnotation } from "../../annotations/ElementDrivesTextAnnotation";
17
+ import { ElementDrivesTextAnnotation, TextAnnotationUsesTextStyleByDefault } from "../../annotations/ElementDrivesTextAnnotation";
18
+ function isIntlSupported() {
19
+ // Node in the mobile add-on does not include Intl, so this test fails. Right now, mobile
20
+ // users are not expected to do any editing, but long term we will attempt to find a better
21
+ // solution.
22
+ return !ProcessDetector.isMobileAppBackend;
23
+ }
18
24
  describe("updateField", () => {
19
25
  const mockElementId = "0x1";
20
26
  const mockPath = {
@@ -31,7 +37,7 @@ describe("updateField", () => {
31
37
  propertyPath.accessors?.[0] === 0 &&
32
38
  propertyPath.accessors?.[1] === "nestedProperty" &&
33
39
  propertyValue !== undefined) {
34
- return { value: propertyValue, metadata: {} };
40
+ return { value: propertyValue, type: "string" };
35
41
  }
36
42
  return undefined;
37
43
  },
@@ -102,6 +108,11 @@ const fieldsSchemaXml = `
102
108
  <ECSchema schemaName="Fields" alias="ts" version="01.00.00" xmlns="http://www.bentley.com/schemas/Bentley.ECXML.3.2">
103
109
  <ECSchemaReference name="BisCore" version="01.00.04" alias="bis"/>
104
110
 
111
+ <ECEnumeration typeName="IntEnum" backingTypeName="int">
112
+ <ECEnumerator name="one" displayLabel="One" value="1" />
113
+ <ECEnumerator name="two" displayLabel="Two" value="2"/>
114
+ </ECEnumeration>
115
+
105
116
  <ECStructClass typeName="InnerStruct" modifier="None">
106
117
  <ECProperty propertyName="bool" typeName="boolean"/>
107
118
  <ECArrayProperty propertyName="doubles" typeName="double" minOccurs="0" maxOccurs="unbounded"/>
@@ -117,9 +128,11 @@ const fieldsSchemaXml = `
117
128
  <ECProperty propertyName="intProp" typeName="int"/>
118
129
  <ECProperty propertyName="point" typeName="point3d"/>
119
130
  <ECProperty propertyName="maybeNull" typeName="int"/>
131
+ <ECProperty propertyName="datetime" typeName="dateTime"/>
120
132
  <ECArrayProperty propertyName="strings" typeName="string" minOccurs="0" maxOccurs="unbounded"/>
121
133
  <ECStructProperty propertyName="outerStruct" typeName="OuterStruct"/>
122
134
  <ECStructArrayProperty propertyName="outerStructs" typeName="OuterStruct" minOccurs="0" maxOccurs="unbounded"/>
135
+ <ECProperty propertyName="intEnum" typeName="IntEnum"/>
123
136
  </ECEntityClass>
124
137
 
125
138
  <ECEntityClass typeName="TestAspect" modifier="None">
@@ -174,6 +187,8 @@ describe("Field evaluation", () => {
174
187
  intProp: 100,
175
188
  point: { x: 1, y: 2, z: 3 },
176
189
  strings: ["a", "b", `"name": "c"`],
190
+ datetime: new Date("2025-08-28T13:45:30.123Z"),
191
+ intEnum: 1,
177
192
  outerStruct: {
178
193
  innerStruct: { bool: false, doubles: [1, 2, 3] },
179
194
  innerStructs: [{ bool: true, doubles: [] }, { bool: false, doubles: [5, 4, 3, 2, 1] }],
@@ -189,6 +204,7 @@ describe("Field evaluation", () => {
189
204
  jsonProperties: {
190
205
  stringProp: "abc",
191
206
  ints: [10, 11, 12, 13],
207
+ bool: true,
192
208
  zoo: {
193
209
  address: {
194
210
  zipcode: 12345,
@@ -210,22 +226,27 @@ describe("Field evaluation", () => {
210
226
  imodel.saveChanges();
211
227
  return id;
212
228
  }
229
+ function evaluateField(propertyPath, propertyHost, deletedDependency = false) {
230
+ if (typeof propertyHost === "string") {
231
+ propertyHost = { schemaName: "Fields", className: "TestElement", elementId: propertyHost };
232
+ }
233
+ const field = FieldRun.create({
234
+ propertyPath,
235
+ propertyHost,
236
+ });
237
+ const context = createUpdateContext(propertyHost.elementId, imodel, deletedDependency);
238
+ return context.getProperty(field);
239
+ }
213
240
  describe("getProperty", () => {
214
241
  function expectValue(expected, propertyPath, propertyHost, deletedDependency = false) {
215
- if (typeof propertyHost === "string") {
216
- propertyHost = { schemaName: "Fields", className: "TestElement", elementId: propertyHost };
217
- }
218
- const field = FieldRun.create({
219
- propertyPath,
220
- propertyHost,
221
- });
222
- const context = createUpdateContext(propertyHost.elementId, imodel, deletedDependency);
223
- const actual = context.getProperty(field);
224
- expect(actual?.value).to.deep.equal(expected);
242
+ expect(evaluateField(propertyPath, propertyHost, deletedDependency)?.value).to.deep.equal(expected);
225
243
  }
226
244
  it("returns a primitive property value", () => {
227
245
  expectValue(100, { propertyName: "intProp" }, sourceElementId);
228
246
  });
247
+ it("returns an integer enum property value", () => {
248
+ expectValue(1, { propertyName: "intEnum" }, sourceElementId);
249
+ });
229
250
  it("treats points as primitive values", () => {
230
251
  expectValue({ x: 1, y: 2, z: 3 }, { propertyName: "point" }, sourceElementId);
231
252
  expectValue(undefined, { propertyName: "point", accessors: ["x"] }, sourceElementId);
@@ -284,28 +305,62 @@ describe("Field evaluation", () => {
284
305
  expectValue(false, { propertyName: "outerStructs", accessors: [0, "innerStructs", -1, "bool"] }, sourceElementId);
285
306
  expectValue(5, { propertyName: "outerStructs", accessors: [0, "innerStructs", 0, "doubles", 0] }, sourceElementId);
286
307
  });
287
- it("returns arbitrarily-nested JSON properties", () => {
288
- expectValue("abc", { propertyName: "jsonProperties", jsonAccessors: ["stringProp"] }, sourceElementId);
289
- expectValue(10, { propertyName: "jsonProperties", jsonAccessors: ["ints", 0] }, sourceElementId);
290
- expectValue(13, { propertyName: "jsonProperties", jsonAccessors: ["ints", 3] }, sourceElementId);
291
- expectValue(13, { propertyName: "jsonProperties", jsonAccessors: ["ints", -1] }, sourceElementId);
292
- expectValue(11, { propertyName: "jsonProperties", jsonAccessors: ["ints", -3] }, sourceElementId);
293
- expectValue(12345, { propertyName: "jsonProperties", jsonAccessors: ["zoo", "address", "zipcode"] }, sourceElementId);
294
- expectValue("scree!", { propertyName: "jsonProperties", jsonAccessors: ["zoo", "birds", 1, "sound"] }, sourceElementId);
295
- });
296
- it("returns undefined if JSON accessors applied to non-JSON property", () => {
297
- expectValue(undefined, { propertyName: "int", jsonAccessors: ["whatever"] }, sourceElementId);
298
- expectValue(undefined, { propertyName: "strings", accessors: [2, "name"] }, sourceElementId);
299
- expectValue(undefined, { propertyName: "outerStruct", accessors: ["innerStruct"], jsonAccessors: ["bool"] }, sourceElementId);
300
- });
301
308
  it("returns the value of a property of an aspect", () => {
302
309
  expect(imodel.elements.getAspects(sourceElementId, "Fields:TestAspect").length).to.equal(1);
303
310
  expectValue(999, { propertyName: "aspectProp" }, { elementId: sourceElementId, schemaName: "Fields", className: "TestAspect" });
304
311
  });
312
+ it("should fail to evaluate if prop type does not match", () => {
313
+ const fieldRun = FieldRun.create({
314
+ propertyHost: { elementId: sourceElementId, schemaName: "Fields", className: "TestElement" },
315
+ propertyPath: { propertyName: "string", accessors: [0] },
316
+ cachedContent: "oldValue",
317
+ formatOptions: {
318
+ case: "upper",
319
+ prefix: "Value: ",
320
+ suffix: "!"
321
+ }
322
+ });
323
+ const context = createUpdateContext(sourceElementId, imodel, false);
324
+ const updated = updateField(fieldRun, context);
325
+ expect(updated).to.be.true;
326
+ expect(fieldRun.cachedContent).to.equal(FieldRun.invalidContentIndicator);
327
+ });
328
+ function getPropertyType(propertyHost, propertyPath) {
329
+ if (typeof propertyPath === "string") {
330
+ propertyPath = { propertyName: propertyPath };
331
+ }
332
+ return evaluateField(propertyPath, propertyHost)?.type;
333
+ }
334
+ it("deduces type for primitive properties", () => {
335
+ const propertyHost = { elementId: sourceElementId, schemaName: "Fields", className: "TestElement" };
336
+ expect(getPropertyType(propertyHost, "intProp")).to.equal("string");
337
+ expect(getPropertyType(propertyHost, "point")).to.equal("coordinate");
338
+ expect(getPropertyType(propertyHost, { propertyName: "strings", accessors: [0] })).to.equal("string");
339
+ expect(getPropertyType(propertyHost, "intEnum")).to.equal("int-enum");
340
+ expect(getPropertyType(propertyHost, { propertyName: "outerStruct", accessors: ["innerStruct", "doubles", 0] })).to.equal("quantity");
341
+ expect(getPropertyType(propertyHost, { propertyName: "outerStruct", accessors: ["innerStruct", "bool"] })).to.equal("boolean");
342
+ propertyHost.schemaName = "BisCore";
343
+ propertyHost.className = "GeometricElement3d";
344
+ expect(getPropertyType(propertyHost, "LastMod")).to.equal("datetime");
345
+ expect(getPropertyType(propertyHost, "FederationGuid")).to.equal("string");
346
+ });
347
+ it("returns undefined for non-primitive properties", () => {
348
+ const propertyHost = { elementId: sourceElementId, schemaName: "Fields", className: "TestElement" };
349
+ expect(getPropertyType(propertyHost, "outerStruct")).to.equal(undefined);
350
+ expect(getPropertyType(propertyHost, "outerStructs")).to.equal(undefined);
351
+ });
352
+ it("returns undefined for invalid property paths", () => {
353
+ const propertyHost = { elementId: sourceElementId, schemaName: "Fields", className: "TestElement" };
354
+ expect(getPropertyType(propertyHost, "unknownPropertyName")).to.be.undefined;
355
+ });
356
+ it("should return undefined for unsupported primitive types", () => {
357
+ const host = { elementId: sourceElementId, schemaName: "BisCore", className: "GeometricElement3d" };
358
+ expect(getPropertyType(host, "GeometryStream")).to.be.undefined;
359
+ });
305
360
  });
306
361
  describe("updateFields", () => {
307
362
  it("recomputes cached content", () => {
308
- const textBlock = TextBlock.create({ styleId: "0x123" });
363
+ const textBlock = TextBlock.create();
309
364
  const fieldRun = FieldRun.create({
310
365
  propertyHost: { elementId: sourceElementId, schemaName: "Fields", className: "TestElement" },
311
366
  propertyPath: { propertyName: "intProp" },
@@ -318,7 +373,7 @@ describe("Field evaluation", () => {
318
373
  expect(fieldRun.cachedContent).to.equal("100"); // `intProp` value from the test element
319
374
  });
320
375
  it("does not update a field if recomputed content matches cached content", () => {
321
- const textBlock = TextBlock.create({ styleId: "0x123" });
376
+ const textBlock = TextBlock.create();
322
377
  const fieldRun = FieldRun.create({
323
378
  propertyHost: { elementId: sourceElementId, schemaName: "Fields", className: "TestElement" },
324
379
  propertyPath: { propertyName: "intProp" },
@@ -331,7 +386,7 @@ describe("Field evaluation", () => {
331
386
  expect(fieldRun.cachedContent).to.equal("100");
332
387
  });
333
388
  it("returns the number of fields updated", () => {
334
- const textBlock = TextBlock.create({ styleId: "0x123" });
389
+ const textBlock = TextBlock.create();
335
390
  const fieldRun1 = FieldRun.create({
336
391
  propertyHost: { elementId: sourceElementId, schemaName: "Fields", className: "TestElement" },
337
392
  propertyPath: { propertyName: "intProp" },
@@ -361,6 +416,7 @@ describe("Field evaluation", () => {
361
416
  angles: YawPitchRollAngles.createDegrees(0, 0, 0).toJSON(),
362
417
  },
363
418
  classFullName: TextAnnotation3d.classFullName,
419
+ defaultTextStyle: new TextAnnotationUsesTextStyleByDefault("0x123").toJSON(),
364
420
  }, imodel);
365
421
  if (textBlock) {
366
422
  const annotation = TextAnnotation.fromJSON({ textBlock: textBlock.toJSON() });
@@ -395,7 +451,7 @@ describe("Field evaluation", () => {
395
451
  expect(relationship.sourceId).to.equal(sourceElementId);
396
452
  expect(relationship.targetId).to.equal(targetId);
397
453
  });
398
- function createField(propertyHost, cachedContent, propertyName = "intProp", accessors, jsonAccessors) {
454
+ function createField(propertyHost, cachedContent, propertyName = "intProp", accessors) {
399
455
  if (typeof propertyHost === "string") {
400
456
  propertyHost = { schemaName: "Fields", className: "TestElement", elementId: propertyHost };
401
457
  }
@@ -403,13 +459,13 @@ describe("Field evaluation", () => {
403
459
  styleOverrides: { fontName: "Karla" },
404
460
  propertyHost,
405
461
  cachedContent,
406
- propertyPath: { propertyName, accessors, jsonAccessors },
462
+ propertyPath: { propertyName, accessors },
407
463
  });
408
464
  }
409
465
  describe("updateFieldDependencies", () => {
410
466
  it("creates exactly one relationship for each unique source element on insert and update", () => {
411
467
  const source1 = insertTestElement();
412
- const block = TextBlock.create({ styleId: "0x123" });
468
+ const block = TextBlock.create();
413
469
  block.appendRun(createField(source1, "1"));
414
470
  const targetId = insertAnnotationElement(block);
415
471
  imodel.saveChanges();
@@ -437,7 +493,7 @@ describe("Field evaluation", () => {
437
493
  it("deletes stale relationships", () => {
438
494
  const sourceA = insertTestElement();
439
495
  const sourceB = insertTestElement();
440
- const block = TextBlock.create({ styleId: "0x123" });
496
+ const block = TextBlock.create();
441
497
  block.appendRun(createField(sourceA, "A"));
442
498
  block.appendRun(createField(sourceB, "B"));
443
499
  const targetId = insertAnnotationElement(block);
@@ -476,7 +532,7 @@ describe("Field evaluation", () => {
476
532
  });
477
533
  it("ignores invalid source element Ids", () => {
478
534
  const source = insertTestElement();
479
- const block = TextBlock.create({ styleId: "0x123" });
535
+ const block = TextBlock.create();
480
536
  block.appendRun(createField(Id64.invalid, "invalid"));
481
537
  block.appendRun(createField("0xbaadf00d", "non-existent"));
482
538
  block.appendRun(createField(source, "valid"));
@@ -491,9 +547,19 @@ describe("Field evaluation", () => {
491
547
  const actual = anno.textBlock.stringify();
492
548
  expect(actual).to.equal(expected);
493
549
  }
550
+ it("evaluates cachedContent when annotation element is inserted", () => {
551
+ const sourceId = insertTestElement();
552
+ const block = TextBlock.create();
553
+ block.appendRun(createField(sourceId, "initial cached content"));
554
+ expect(block.stringify()).to.equal("initial cached content");
555
+ const targetId = insertAnnotationElement(block);
556
+ imodel.saveChanges();
557
+ const target = imodel.elements.getElement(targetId);
558
+ expect(target.getAnnotation().textBlock.stringify()).to.equal("100");
559
+ });
494
560
  it("updates fields when source element is modified or deleted", () => {
495
561
  const sourceId = insertTestElement();
496
- const block = TextBlock.create({ styleId: "0x123" });
562
+ const block = TextBlock.create();
497
563
  block.appendRun(createField(sourceId, "old value"));
498
564
  ;
499
565
  const targetId = insertAnnotationElement(block);
@@ -516,7 +582,7 @@ describe("Field evaluation", () => {
516
582
  });
517
583
  it("updates fields when source element aspect is modified, deleted, or recreated", () => {
518
584
  const sourceId = insertTestElement();
519
- const block = TextBlock.create({ styleId: "0x123" });
585
+ const block = TextBlock.create();
520
586
  block.appendRun(createField({ elementId: sourceId, schemaName: "Fields", className: "TestAspect" }, "", "aspectProp"));
521
587
  const targetId = insertAnnotationElement(block);
522
588
  imodel.saveChanges();
@@ -544,7 +610,7 @@ describe("Field evaluation", () => {
544
610
  it("updates only fields for specific modified element", () => {
545
611
  const sourceA = insertTestElement();
546
612
  const sourceB = insertTestElement();
547
- const block = TextBlock.create({ styleId: "0x123" });
613
+ const block = TextBlock.create();
548
614
  block.appendRun(createField(sourceA, "A"));
549
615
  block.appendRun(createField(sourceB, "B"));
550
616
  const targetId = insertAnnotationElement(block);
@@ -558,18 +624,67 @@ describe("Field evaluation", () => {
558
624
  });
559
625
  it("supports complex property paths", () => {
560
626
  const sourceId = insertTestElement();
561
- const block = TextBlock.create({ styleId: "0x123" });
627
+ const block = TextBlock.create();
562
628
  block.appendRun(createField(sourceId, "", "outerStruct", ["innerStructs", 1, "doubles", -2]));
563
- block.appendRun(createField(sourceId, "", "jsonProperties", undefined, ["zoo", "birds", 0, "name"]));
564
629
  const targetId = insertAnnotationElement(block);
565
630
  imodel.saveChanges();
566
- expectText("2duck", targetId);
631
+ expectText("2", targetId);
567
632
  const source = imodel.elements.getElement(sourceId);
568
633
  source.outerStruct.innerStructs[1].doubles[3] = 12.5;
569
- source.jsonProperties.zoo.birds[0].name = "parrot";
570
634
  source.update();
571
635
  imodel.saveChanges();
572
- expectText("12.5parrot", targetId);
636
+ expectText("12.5", targetId);
637
+ });
638
+ });
639
+ describe("Format Validation", () => {
640
+ it("validates formatting options for string property type", () => {
641
+ // Create a FieldRun with string property type and some format options
642
+ const fieldRun = FieldRun.create({
643
+ propertyHost: { elementId: sourceElementId, schemaName: "Fields", className: "TestElement" },
644
+ propertyPath: { propertyName: "strings", accessors: [0] },
645
+ cachedContent: "oldValue",
646
+ formatOptions: {
647
+ case: "upper",
648
+ prefix: "Value: ",
649
+ suffix: "!"
650
+ }
651
+ });
652
+ // Context returns a string value for the property
653
+ const context = {
654
+ hostElementId: sourceElementId,
655
+ getProperty: () => { return { value: "abc", type: "string" }; },
656
+ };
657
+ // Update the field and check the result
658
+ const updated = updateField(fieldRun, context);
659
+ // The formatted value should be uppercased and have prefix/suffix applied
660
+ expect(updated).to.be.true;
661
+ expect(fieldRun.cachedContent).to.equal("Value: ABC!");
662
+ });
663
+ it("validates formatting options for datetime objects", function () {
664
+ if (!isIntlSupported()) {
665
+ this.skip();
666
+ }
667
+ const propertyHost = { elementId: sourceElementId, schemaName: "Fields", className: "TestElement" };
668
+ const fieldRun = FieldRun.create({
669
+ propertyHost,
670
+ propertyPath: { propertyName: "datetime" },
671
+ cachedContent: "oldval",
672
+ formatOptions: {
673
+ dateTime: {
674
+ formatOptions: {
675
+ month: "short",
676
+ day: "2-digit",
677
+ year: "numeric",
678
+ timeZone: "UTC"
679
+ },
680
+ locale: "en-US",
681
+ },
682
+ },
683
+ });
684
+ const context = createUpdateContext(sourceElementId, imodel, false);
685
+ const updated = updateField(fieldRun, context);
686
+ expect(updated).to.be.true;
687
+ expect(fieldRun.cachedContent).to.equal("Aug 28, 2025");
573
688
  });
574
689
  });
575
690
  });