bruce-models 5.9.6 → 5.9.8

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 (38) hide show
  1. package/dist/bruce-models.es5.js +160 -104
  2. package/dist/bruce-models.es5.js.map +1 -1
  3. package/dist/bruce-models.umd.js +160 -104
  4. package/dist/bruce-models.umd.js.map +1 -1
  5. package/dist/lib/api/api.js.map +1 -1
  6. package/dist/lib/bruce-models.js +1 -1
  7. package/dist/lib/calculator/calculator.js +25 -13
  8. package/dist/lib/calculator/calculator.js.map +1 -1
  9. package/dist/lib/common/bruce-event.js +8 -3
  10. package/dist/lib/common/bruce-event.js.map +1 -1
  11. package/dist/lib/common/bruce-variable.js +31 -38
  12. package/dist/lib/common/bruce-variable.js.map +1 -1
  13. package/dist/lib/common/cache.js +2 -3
  14. package/dist/lib/common/cache.js.map +1 -1
  15. package/dist/lib/common/delay-queue.js +6 -2
  16. package/dist/lib/common/delay-queue.js.map +1 -1
  17. package/dist/lib/common/geometry.js +17 -13
  18. package/dist/lib/common/geometry.js.map +1 -1
  19. package/dist/lib/common/lru-cache.js +7 -1
  20. package/dist/lib/common/lru-cache.js.map +1 -1
  21. package/dist/lib/common/utc.js +15 -7
  22. package/dist/lib/common/utc.js.map +1 -1
  23. package/dist/lib/entity/entity-attribute.js +4 -1
  24. package/dist/lib/entity/entity-attribute.js.map +1 -1
  25. package/dist/lib/entity/entity.js +33 -5
  26. package/dist/lib/entity/entity.js.map +1 -1
  27. package/dist/lib/util/math-utils.js +7 -7
  28. package/dist/lib/util/math-utils.js.map +1 -1
  29. package/dist/lib/util/path-utils.js +6 -5
  30. package/dist/lib/util/path-utils.js.map +1 -1
  31. package/dist/types/api/api.d.ts +2 -2
  32. package/dist/types/bruce-models.d.ts +1 -1
  33. package/dist/types/calculator/calculator.d.ts +1 -1
  34. package/dist/types/common/bruce-variable.d.ts +1 -0
  35. package/dist/types/common/delay-queue.d.ts +2 -1
  36. package/dist/types/entity/entity.d.ts +32 -29
  37. package/dist/types/util/math-utils.d.ts +1 -1
  38. package/package.json +1 -1
@@ -155,8 +155,6 @@
155
155
  Api.PrepReqParams = PrepReqParams;
156
156
  })(exports.Api || (exports.Api = {}));
157
157
 
158
- // 1 minute.
159
- const DEFAULT_DURATION = 60 * 1000;
160
158
  class CacheControl {
161
159
  constructor(id) {
162
160
  this.memory = new Map();
@@ -177,7 +175,7 @@
177
175
  }
178
176
  let { id, data, duration } = params;
179
177
  if (!duration || duration < 0) {
180
- duration = DEFAULT_DURATION;
178
+ duration = exports.Api.DEFAULT_CACHE_DURATION;
181
179
  }
182
180
  id = String(id);
183
181
  const expires = Date.now() + duration;
@@ -1638,6 +1636,10 @@
1638
1636
  Unsubscribe(id) {
1639
1637
  let index = this.callbacks.findIndex(x => x._id == id);
1640
1638
  if (index > -1) {
1639
+ // Null the callback function to prevent it from being called.
1640
+ // This stops a trigger from calling it if it's currently looping.
1641
+ this.callbacks[index].callback = null;
1642
+ // Remove the callback from the list.
1641
1643
  this.callbacks.splice(index, 1);
1642
1644
  }
1643
1645
  }
@@ -1647,9 +1649,10 @@
1647
1649
  * @param data
1648
1650
  */
1649
1651
  Trigger(data) {
1650
- let callbacks = this.callbacks;
1651
- for (let i = 0; i < callbacks.length; i++) {
1652
- let callback = callbacks[i];
1652
+ // We copy in case the callback modifies the list.
1653
+ const callbacksCopy = [...this.callbacks];
1654
+ for (let i = 0; i < callbacksCopy.length; i++) {
1655
+ const callback = callbacksCopy[i];
1653
1656
  if (callback.callback) {
1654
1657
  callback.callback(data);
1655
1658
  }
@@ -2544,7 +2547,10 @@
2544
2547
  }
2545
2548
  const key = path[0];
2546
2549
  const item = items.find((i) => i.Key === key);
2547
- if (!item || !item.Structure || !path.length) {
2550
+ if (!item) {
2551
+ return null;
2552
+ }
2553
+ if (path.length === 1) {
2548
2554
  return item;
2549
2555
  }
2550
2556
  return GetAttribute(item.Structure, path.slice(1));
@@ -3128,13 +3134,14 @@
3128
3134
  }
3129
3135
  const broken = str.split(".");
3130
3136
  for (let i = 0; i < broken.length; i++) {
3131
- let piece = broken[0];
3132
- if (piece.charAt(0) == "\"") {
3133
- piece = broken[0] = piece.substring(1);
3137
+ let piece = broken[i];
3138
+ if (piece.startsWith("\"")) {
3139
+ piece = piece.substring(1);
3134
3140
  }
3135
- if (piece.charAt(piece.length - 1) == "\"") {
3136
- broken[0] = piece.substring(0, piece.length - 1);
3141
+ if (piece.endsWith("\"")) {
3142
+ piece = piece.substring(0, piece.length - 1);
3137
3143
  }
3144
+ broken[i] = piece;
3138
3145
  }
3139
3146
  return broken;
3140
3147
  }
@@ -3792,7 +3799,7 @@
3792
3799
  function GetValue(params) {
3793
3800
  var _a;
3794
3801
  let { entity: data, path, handleLegacy: checkAgainstLegacy } = params;
3795
- if (checkAgainstLegacy == null) {
3802
+ if (checkAgainstLegacy == null || checkAgainstLegacy == undefined) {
3796
3803
  checkAgainstLegacy = true;
3797
3804
  }
3798
3805
  if (!path || !path.length) {
@@ -4032,7 +4039,7 @@
4032
4039
  OrderBy: filter.orderBy,
4033
4040
  Filter: requestFilter,
4034
4041
  LODType: filter.lodCategoryId,
4035
- BruceEntityType: filter.entityTypeId,
4042
+ BruceEntityType: (!filter.entityTypeId ? null : filter.entityTypeId),
4036
4043
  PageIndex: filter.pageIndex,
4037
4044
  PageSize: filter.pageSize,
4038
4045
  historicKey: historicKey,
@@ -4084,7 +4091,7 @@
4084
4091
  urlParams.set("LODType", body.LODType);
4085
4092
  }
4086
4093
  if (body.BruceEntityType) {
4087
- urlParams.set("BruceEntityType", body.BruceEntityType);
4094
+ urlParams.set("BruceEntityType", typeof body.BruceEntityType == "string" ? body.BruceEntityType : body.BruceEntityType.join(","));
4088
4095
  }
4089
4096
  if (body.PageIndex) {
4090
4097
  urlParams.set("PageIndex", String(body.PageIndex));
@@ -4183,7 +4190,7 @@
4183
4190
  expandLocation,
4184
4191
  expandImports,
4185
4192
  expandSources,
4186
- entityTypeId: filter.entityTypeId,
4193
+ entityTypeId: typeof filter.entityTypeId == "string" ? filter.entityTypeId : filter.entityTypeId.join(","),
4187
4194
  historicFrom: historicFrom,
4188
4195
  historicKey: historicKey,
4189
4196
  historicTo: historicTo,
@@ -4202,12 +4209,40 @@
4202
4209
  nextPage = data.NextPage;
4203
4210
  nextPageUrl = data.NextPageURL;
4204
4211
  }
4212
+ // Callback to get the next page.
4213
+ let getNextPage;
4214
+ if (nextPage) {
4215
+ getNextPage = () => __awaiter(this, void 0, void 0, function* () {
4216
+ let urlStr = null;
4217
+ if (nextPageUrl.startsWith("http")) {
4218
+ urlStr = nextPageUrl;
4219
+ }
4220
+ else {
4221
+ urlStr = api.ConstructUrl({
4222
+ cdn: false,
4223
+ url: nextPageUrl
4224
+ });
4225
+ }
4226
+ const data = yield api.get(urlStr, exports.Api.PrepReqParams(reqParams));
4227
+ // Update URL so we can re-use the same function instance.
4228
+ nextPageUrl = data.NextPageURL;
4229
+ return {
4230
+ entities: data.Items,
4231
+ totalCount: data.TotalCount,
4232
+ imports: data.Imports,
4233
+ nextPage: data.NextPage,
4234
+ nextPageUrl: data.NextPageURL,
4235
+ getNextPage: nextPageUrl ? getNextPage : null
4236
+ };
4237
+ });
4238
+ }
4205
4239
  return {
4206
4240
  entities,
4207
4241
  totalCount,
4208
4242
  imports,
4209
4243
  nextPage,
4210
- nextPageUrl
4244
+ nextPageUrl,
4245
+ getNextPage
4211
4246
  };
4212
4247
  });
4213
4248
  }
@@ -4309,25 +4344,6 @@
4309
4344
  Entity.GetHistoricContainsKey = GetHistoricContainsKey;
4310
4345
  })(exports.Entity || (exports.Entity = {}));
4311
4346
 
4312
- /**
4313
- * Gets the first Bruce variable in a string.
4314
- * @param str
4315
- * @returns
4316
- */
4317
- function getVariable(str) {
4318
- const start = str.indexOf("${");
4319
- if (start > -1) {
4320
- const end = str.indexOf("}");
4321
- if (end > -1) {
4322
- if (start < end) {
4323
- const path = str.substring(start + 2, end);
4324
- const txt = str.substring(start, end + 1);
4325
- return { path: path, text: txt };
4326
- }
4327
- }
4328
- }
4329
- return null;
4330
- }
4331
4347
  (function (BruceVariable) {
4332
4348
  /**
4333
4349
  * Replaces all Bruce variables in a string with the value of the attribute.
@@ -4337,28 +4353,40 @@
4337
4353
  * @returns
4338
4354
  */
4339
4355
  function SwapValues(params) {
4340
- let { str, entity: data, legacyParse } = params;
4341
- if (!legacyParse) {
4342
- legacyParse = false;
4343
- }
4344
- while (true) {
4345
- const variable = getVariable(str);
4346
- if (variable) {
4347
- const path = legacyParse ? exports.PathUtils.ParseLegacy(variable.path) : exports.PathUtils.Parse(variable.path);
4348
- let value = "";
4349
- if (path.length > 0) {
4350
- value = exports.Entity.GetValue({
4351
- entity: data,
4352
- path: path
4353
- });
4354
- }
4355
- str = str.replace(variable.text, value);
4356
+ const { str, entity: data, legacyParse, retainType } = params;
4357
+ // If the input is just a path, return the value of the path.
4358
+ // We only do this for 'retainType=true' because all existing code expects a string result.
4359
+ if (retainType && str.startsWith("${") && str.endsWith("}")) {
4360
+ let pathStr = str.slice(2, -1);
4361
+ pathStr = pathStr.trim();
4362
+ const path = legacyParse ? exports.PathUtils.ParseLegacy(pathStr) : exports.PathUtils.Parse(pathStr);
4363
+ return exports.Entity.GetValue({
4364
+ entity: data,
4365
+ path: path
4366
+ });
4367
+ }
4368
+ // Regex that will match all Bruce variables.
4369
+ // It looks for ${...} and captures the content inside the brackets.
4370
+ const variableRegex = /\${([^}]*)}/g;
4371
+ return str.replace(variableRegex, (match, pathStr) => {
4372
+ // If the path is empty or just whitespace, return empty string
4373
+ if (!pathStr || pathStr.trim().length === 0) {
4374
+ return "";
4356
4375
  }
4357
- else {
4358
- break;
4376
+ pathStr = pathStr.trim();
4377
+ const path = legacyParse ? exports.PathUtils.ParseLegacy(pathStr) : exports.PathUtils.Parse(pathStr);
4378
+ if (!path.length) {
4379
+ return "";
4359
4380
  }
4360
- }
4361
- return str;
4381
+ const value = exports.Entity.GetValue({
4382
+ entity: data,
4383
+ path: path
4384
+ });
4385
+ if (value == null || value == undefined) {
4386
+ return "";
4387
+ }
4388
+ return String(value);
4389
+ });
4362
4390
  }
4363
4391
  BruceVariable.SwapValues = SwapValues;
4364
4392
  })(exports.BruceVariable || (exports.BruceVariable = {}));
@@ -4437,6 +4465,11 @@
4437
4465
  */
4438
4466
  function Calculate(params) {
4439
4467
  let { fields, tags, data, defaultValue, type } = params;
4468
+ // If params doesn't include a defaultValue, use null.
4469
+ // Though passing in undefined is valid!
4470
+ if ("defaultValue" in params == false) {
4471
+ defaultValue = null;
4472
+ }
4440
4473
  if (fields == null) {
4441
4474
  return defaultValue;
4442
4475
  }
@@ -4487,11 +4520,6 @@
4487
4520
  let value = null;
4488
4521
  for (let i = 0; i < fieldsArr.length; i++) {
4489
4522
  let field = fieldsArr[i];
4490
- if (field) {
4491
- // Dereference.
4492
- // We do this because we'll be modifying the field to fix bad data.
4493
- field = JSON.parse(JSON.stringify(field));
4494
- }
4495
4523
  // Bad data has it set to 'color' but expects the input to be a number.
4496
4524
  if (type == "number" && field.type == EValueType.Color) {
4497
4525
  field.type = EValueType.Input;
@@ -4848,20 +4876,26 @@
4848
4876
  try {
4849
4877
  value = exports.BruceVariable.SwapValues({
4850
4878
  str: value,
4851
- entity: entity
4879
+ entity: entity,
4880
+ retainType: true
4852
4881
  });
4853
- const isJsEval = value.startsWith("JS:");
4854
- const MATH_REGEX = /(\d+\.?\d*|\.\d+)([+\-*/])(\d+\.?\d*|\.\d+)/;
4855
- const isMathEval = isJsEval || MATH_REGEX.test(value);
4856
- if (isJsEval || isMathEval) {
4857
- if (isJsEval) {
4858
- value = value.replace("JS:", "");
4859
- value = value.trim();
4882
+ if (value == null || value == undefined) {
4883
+ return null;
4884
+ }
4885
+ if (typeof value === "string") {
4886
+ const isJsEval = value.startsWith("JS:");
4887
+ const MATH_REGEX = /(\d+\.?\d*|\.\d+)([+\-*/])(\d+\.?\d*|\.\d+)/;
4888
+ const isMathEval = isJsEval || MATH_REGEX.test(value);
4889
+ if (isJsEval || isMathEval) {
4890
+ if (isJsEval) {
4891
+ value = value.replace("JS:", "");
4892
+ value = value.trim();
4893
+ }
4894
+ // https://rollupjs.org/guide/en/#avoiding-eval
4895
+ // This stops eval warning.
4896
+ const eval2 = eval;
4897
+ return eval2(value);
4860
4898
  }
4861
- // https://rollupjs.org/guide/en/#avoiding-eval
4862
- // This stops eval warning.
4863
- const eval2 = eval;
4864
- return eval2(value);
4865
4899
  }
4866
4900
  }
4867
4901
  catch (exception) {
@@ -4915,13 +4949,7 @@
4915
4949
  if (!points.length) {
4916
4950
  throw ("points is empty.");
4917
4951
  }
4918
- let carto = points[0];
4919
- let lineString = `${carto.longitude},${carto.latitude}` + (carto.altitude != null ? `,${carto.altitude}` : "");
4920
- for (let i = 1; i < points.length; i++) {
4921
- carto = points[i];
4922
- lineString += ` ${carto.longitude},${carto.latitude}` + (carto.altitude != null ? `,${carto.altitude}` : "");
4923
- }
4924
- return lineString;
4952
+ return points.map(carto => `${carto.longitude},${carto.latitude}` + (carto.altitude != null ? `,${carto.altitude}` : "")).join(' ');
4925
4953
  }
4926
4954
  Geometry.LineStrFromPoints = LineStrFromPoints;
4927
4955
  /**
@@ -5013,6 +5041,9 @@
5013
5041
  }
5014
5042
  return newGeometry;
5015
5043
  }
5044
+ else if (!geometry) {
5045
+ return {};
5046
+ }
5016
5047
  return geometry;
5017
5048
  }
5018
5049
  Geometry.ParseGeometry = ParseGeometry;
@@ -5029,19 +5060,26 @@
5029
5060
  const collection = [];
5030
5061
  // Returns if two coordinates are equal.
5031
5062
  const areCoordinatesEqual = (coord1, coord2) => {
5032
- return coord1[0] === coord2[0] && coord1[1] === coord2[1] && coord1[2] === coord2[2];
5063
+ return coord1[0] === coord2[0] && coord1[1] === coord2[1] &&
5064
+ (noAltitude || coord1[2] === coord2[2]);
5033
5065
  };
5034
5066
  // Removes consecutive duplicate coordinates.
5035
5067
  const removeConsecutiveDuplicates = (coordinates) => {
5036
- return coordinates.filter((coord, index) => {
5037
- return index === 0 || !areCoordinatesEqual(coord, coordinates[index - 1]);
5038
- });
5068
+ if (coordinates.length <= 1)
5069
+ return coordinates;
5070
+ const result = [coordinates[0]];
5071
+ for (let i = 1; i < coordinates.length; i++) {
5072
+ if (!areCoordinatesEqual(coordinates[i], coordinates[i - 1])) {
5073
+ result.push(coordinates[i]);
5074
+ }
5075
+ }
5076
+ return result;
5039
5077
  };
5040
5078
  // Ensures that the polygon is closed.
5041
5079
  const closePolygonCoordinates = (coordinates) => {
5042
5080
  return coordinates.map(ring => {
5043
- if (!areCoordinatesEqual(ring[0], ring[ring.length - 1])) {
5044
- ring.push(ring[0]);
5081
+ if (ring.length > 0 && !areCoordinatesEqual(ring[0], ring[ring.length - 1])) {
5082
+ return [...ring, ring[0]];
5045
5083
  }
5046
5084
  return ring;
5047
5085
  });
@@ -5631,13 +5669,14 @@
5631
5669
  * If you have a method that may be called often, but you don't want it to run often, use this.
5632
5670
  */
5633
5671
  class DelayQueue {
5634
- constructor(callback, delay = 200) {
5672
+ constructor(callback, delay = 200, startDelayed = false) {
5635
5673
  // Millisecond delay.
5636
5674
  this.delay = 200;
5637
5675
  // Date-time stamp for the last callback call.
5638
5676
  this.lastCallTime = null;
5639
5677
  this.callback = callback;
5640
5678
  this.delay = delay;
5679
+ this.startDelayed = startDelayed;
5641
5680
  }
5642
5681
  /**
5643
5682
  * Request a call on the callback.
@@ -5645,7 +5684,10 @@
5645
5684
  */
5646
5685
  Call(force = false) {
5647
5686
  if (this.lastCallTime == null) {
5648
- force = true;
5687
+ this.lastCallTime = new Date().getTime();
5688
+ if (this.startDelayed) {
5689
+ force = false;
5690
+ }
5649
5691
  }
5650
5692
  if (force) {
5651
5693
  let endDate = new Date().getTime();
@@ -5749,28 +5791,36 @@
5749
5791
  * @param utc
5750
5792
  */
5751
5793
  function GetPassedTime(utc) {
5752
- const passedSeconds = GetPassedSeconds(utc);
5794
+ let tense = "ago";
5795
+ let passedSeconds = GetPassedSeconds(utc);
5796
+ if (passedSeconds < 0) {
5797
+ // Account for the time difference between the client and the server.
5798
+ if (passedSeconds < -(15 * 60)) {
5799
+ return "recently";
5800
+ }
5801
+ tense = "from now";
5802
+ }
5753
5803
  if (passedSeconds < 60) {
5754
- return `${passedSeconds} second${passedSeconds > 1 ? "s" : ""} ago`;
5804
+ return `${passedSeconds} second${passedSeconds > 1 ? "s" : ""} ${tense}`;
5755
5805
  }
5756
5806
  const passedMinutes = Math.floor(passedSeconds / 60);
5757
5807
  if (passedMinutes < 60) {
5758
- return `${passedMinutes} minute${passedMinutes > 1 ? "s" : ""} ago`;
5808
+ return `${passedMinutes} minute${passedMinutes > 1 ? "s" : ""} ${tense}`;
5759
5809
  }
5760
5810
  const passedHours = Math.floor(passedMinutes / 60);
5761
5811
  if (passedHours < 24) {
5762
- return `${passedHours} hour${passedHours > 1 ? "s" : ""} ago`;
5812
+ return `${passedHours} hour${passedHours > 1 ? "s" : ""} ${tense}`;
5763
5813
  }
5764
5814
  const passedDays = Math.floor(passedHours / 24);
5765
5815
  if (passedDays < 30) {
5766
- return `${passedDays} day${passedDays > 1 ? "s" : ""} ago`;
5816
+ return `${passedDays} day${passedDays > 1 ? "s" : ""} ${tense}`;
5767
5817
  }
5768
5818
  const passedMonths = Math.floor(passedDays / 30);
5769
5819
  if (passedMonths < 12) {
5770
- return `${passedMonths} month${passedMonths > 1 ? "s" : ""} ago`;
5820
+ return `${passedMonths} month${passedMonths > 1 ? "s" : ""} ${tense}`;
5771
5821
  }
5772
5822
  const passedYears = Math.floor(passedMonths / 12);
5773
- return `${passedYears} year${passedYears > 1 ? "s" : ""} ago`;
5823
+ return `${passedYears} year${passedYears > 1 ? "s" : ""} ${tense}`;
5774
5824
  }
5775
5825
  UTC.GetPassedTime = GetPassedTime;
5776
5826
  /**
@@ -5851,7 +5901,13 @@
5851
5901
  * @param value
5852
5902
  */
5853
5903
  Set(key, value) {
5854
- if (this.cache.size >= this.capacity) {
5904
+ if (this.capacity <= 0) {
5905
+ // Empty cache.
5906
+ // Means we were configured to not cache anything.
5907
+ this.cache.clear();
5908
+ return;
5909
+ }
5910
+ else if (this.cache.size >= this.capacity) {
5855
5911
  const leastRecentlyUsedKey = this.cache.keys().next().value;
5856
5912
  this.cache.delete(leastRecentlyUsedKey);
5857
5913
  }
@@ -7561,15 +7617,15 @@
7561
7617
  * @returns
7562
7618
  */
7563
7619
  function Round(num, decimals = 0) {
7564
- if (decimals <= 0) {
7565
- return Math.round(num);
7620
+ const n = typeof num === 'string' ? parseFloat(num) : num;
7621
+ if (isNaN(n)) {
7622
+ return 0;
7566
7623
  }
7567
- let tmp = "1";
7568
- for (let i = 0; i < decimals; i++) {
7569
- tmp += "0";
7624
+ if (decimals <= 0) {
7625
+ return Math.round(n);
7570
7626
  }
7571
- const d = parseFloat(tmp);
7572
- return Math.round((num + Number.EPSILON) * d) / d;
7627
+ const multiplier = Math.pow(10, decimals);
7628
+ return Math.round((n + Number.EPSILON) * multiplier) / multiplier;
7573
7629
  }
7574
7630
  MathUtils.Round = Round;
7575
7631
  /**
@@ -15312,7 +15368,7 @@
15312
15368
  })(exports.Scenario || (exports.Scenario = {}));
15313
15369
 
15314
15370
  // This is updated with the package.json version on build.
15315
- const VERSION = "5.9.6";
15371
+ const VERSION = "5.9.8";
15316
15372
 
15317
15373
  exports.VERSION = VERSION;
15318
15374
  exports.AbstractApi = AbstractApi;