bruce-models 5.9.7 → 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 (37) hide show
  1. package/dist/bruce-models.es5.js +128 -100
  2. package/dist/bruce-models.es5.js.map +1 -1
  3. package/dist/bruce-models.umd.js +128 -100
  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 +1 -1
  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/util/math-utils.d.ts +1 -1
  37. 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) {
@@ -4337,25 +4344,6 @@
4337
4344
  Entity.GetHistoricContainsKey = GetHistoricContainsKey;
4338
4345
  })(exports.Entity || (exports.Entity = {}));
4339
4346
 
4340
- /**
4341
- * Gets the first Bruce variable in a string.
4342
- * @param str
4343
- * @returns
4344
- */
4345
- function getVariable(str) {
4346
- const start = str.indexOf("${");
4347
- if (start > -1) {
4348
- const end = str.indexOf("}");
4349
- if (end > -1) {
4350
- if (start < end) {
4351
- const path = str.substring(start + 2, end);
4352
- const txt = str.substring(start, end + 1);
4353
- return { path: path, text: txt };
4354
- }
4355
- }
4356
- }
4357
- return null;
4358
- }
4359
4347
  (function (BruceVariable) {
4360
4348
  /**
4361
4349
  * Replaces all Bruce variables in a string with the value of the attribute.
@@ -4365,28 +4353,40 @@
4365
4353
  * @returns
4366
4354
  */
4367
4355
  function SwapValues(params) {
4368
- let { str, entity: data, legacyParse } = params;
4369
- if (!legacyParse) {
4370
- legacyParse = false;
4371
- }
4372
- while (true) {
4373
- const variable = getVariable(str);
4374
- if (variable) {
4375
- const path = legacyParse ? exports.PathUtils.ParseLegacy(variable.path) : exports.PathUtils.Parse(variable.path);
4376
- let value = "";
4377
- if (path.length > 0) {
4378
- value = exports.Entity.GetValue({
4379
- entity: data,
4380
- path: path
4381
- });
4382
- }
4383
- 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 "";
4384
4375
  }
4385
- else {
4386
- break;
4376
+ pathStr = pathStr.trim();
4377
+ const path = legacyParse ? exports.PathUtils.ParseLegacy(pathStr) : exports.PathUtils.Parse(pathStr);
4378
+ if (!path.length) {
4379
+ return "";
4387
4380
  }
4388
- }
4389
- 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
+ });
4390
4390
  }
4391
4391
  BruceVariable.SwapValues = SwapValues;
4392
4392
  })(exports.BruceVariable || (exports.BruceVariable = {}));
@@ -4465,6 +4465,11 @@
4465
4465
  */
4466
4466
  function Calculate(params) {
4467
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
+ }
4468
4473
  if (fields == null) {
4469
4474
  return defaultValue;
4470
4475
  }
@@ -4515,11 +4520,6 @@
4515
4520
  let value = null;
4516
4521
  for (let i = 0; i < fieldsArr.length; i++) {
4517
4522
  let field = fieldsArr[i];
4518
- if (field) {
4519
- // Dereference.
4520
- // We do this because we'll be modifying the field to fix bad data.
4521
- field = JSON.parse(JSON.stringify(field));
4522
- }
4523
4523
  // Bad data has it set to 'color' but expects the input to be a number.
4524
4524
  if (type == "number" && field.type == EValueType.Color) {
4525
4525
  field.type = EValueType.Input;
@@ -4876,20 +4876,26 @@
4876
4876
  try {
4877
4877
  value = exports.BruceVariable.SwapValues({
4878
4878
  str: value,
4879
- entity: entity
4879
+ entity: entity,
4880
+ retainType: true
4880
4881
  });
4881
- const isJsEval = value.startsWith("JS:");
4882
- const MATH_REGEX = /(\d+\.?\d*|\.\d+)([+\-*/])(\d+\.?\d*|\.\d+)/;
4883
- const isMathEval = isJsEval || MATH_REGEX.test(value);
4884
- if (isJsEval || isMathEval) {
4885
- if (isJsEval) {
4886
- value = value.replace("JS:", "");
4887
- 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);
4888
4898
  }
4889
- // https://rollupjs.org/guide/en/#avoiding-eval
4890
- // This stops eval warning.
4891
- const eval2 = eval;
4892
- return eval2(value);
4893
4899
  }
4894
4900
  }
4895
4901
  catch (exception) {
@@ -4943,13 +4949,7 @@
4943
4949
  if (!points.length) {
4944
4950
  throw ("points is empty.");
4945
4951
  }
4946
- let carto = points[0];
4947
- let lineString = `${carto.longitude},${carto.latitude}` + (carto.altitude != null ? `,${carto.altitude}` : "");
4948
- for (let i = 1; i < points.length; i++) {
4949
- carto = points[i];
4950
- lineString += ` ${carto.longitude},${carto.latitude}` + (carto.altitude != null ? `,${carto.altitude}` : "");
4951
- }
4952
- return lineString;
4952
+ return points.map(carto => `${carto.longitude},${carto.latitude}` + (carto.altitude != null ? `,${carto.altitude}` : "")).join(' ');
4953
4953
  }
4954
4954
  Geometry.LineStrFromPoints = LineStrFromPoints;
4955
4955
  /**
@@ -5041,6 +5041,9 @@
5041
5041
  }
5042
5042
  return newGeometry;
5043
5043
  }
5044
+ else if (!geometry) {
5045
+ return {};
5046
+ }
5044
5047
  return geometry;
5045
5048
  }
5046
5049
  Geometry.ParseGeometry = ParseGeometry;
@@ -5057,19 +5060,26 @@
5057
5060
  const collection = [];
5058
5061
  // Returns if two coordinates are equal.
5059
5062
  const areCoordinatesEqual = (coord1, coord2) => {
5060
- 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]);
5061
5065
  };
5062
5066
  // Removes consecutive duplicate coordinates.
5063
5067
  const removeConsecutiveDuplicates = (coordinates) => {
5064
- return coordinates.filter((coord, index) => {
5065
- return index === 0 || !areCoordinatesEqual(coord, coordinates[index - 1]);
5066
- });
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;
5067
5077
  };
5068
5078
  // Ensures that the polygon is closed.
5069
5079
  const closePolygonCoordinates = (coordinates) => {
5070
5080
  return coordinates.map(ring => {
5071
- if (!areCoordinatesEqual(ring[0], ring[ring.length - 1])) {
5072
- ring.push(ring[0]);
5081
+ if (ring.length > 0 && !areCoordinatesEqual(ring[0], ring[ring.length - 1])) {
5082
+ return [...ring, ring[0]];
5073
5083
  }
5074
5084
  return ring;
5075
5085
  });
@@ -5659,13 +5669,14 @@
5659
5669
  * If you have a method that may be called often, but you don't want it to run often, use this.
5660
5670
  */
5661
5671
  class DelayQueue {
5662
- constructor(callback, delay = 200) {
5672
+ constructor(callback, delay = 200, startDelayed = false) {
5663
5673
  // Millisecond delay.
5664
5674
  this.delay = 200;
5665
5675
  // Date-time stamp for the last callback call.
5666
5676
  this.lastCallTime = null;
5667
5677
  this.callback = callback;
5668
5678
  this.delay = delay;
5679
+ this.startDelayed = startDelayed;
5669
5680
  }
5670
5681
  /**
5671
5682
  * Request a call on the callback.
@@ -5673,7 +5684,10 @@
5673
5684
  */
5674
5685
  Call(force = false) {
5675
5686
  if (this.lastCallTime == null) {
5676
- force = true;
5687
+ this.lastCallTime = new Date().getTime();
5688
+ if (this.startDelayed) {
5689
+ force = false;
5690
+ }
5677
5691
  }
5678
5692
  if (force) {
5679
5693
  let endDate = new Date().getTime();
@@ -5777,28 +5791,36 @@
5777
5791
  * @param utc
5778
5792
  */
5779
5793
  function GetPassedTime(utc) {
5780
- 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
+ }
5781
5803
  if (passedSeconds < 60) {
5782
- return `${passedSeconds} second${passedSeconds > 1 ? "s" : ""} ago`;
5804
+ return `${passedSeconds} second${passedSeconds > 1 ? "s" : ""} ${tense}`;
5783
5805
  }
5784
5806
  const passedMinutes = Math.floor(passedSeconds / 60);
5785
5807
  if (passedMinutes < 60) {
5786
- return `${passedMinutes} minute${passedMinutes > 1 ? "s" : ""} ago`;
5808
+ return `${passedMinutes} minute${passedMinutes > 1 ? "s" : ""} ${tense}`;
5787
5809
  }
5788
5810
  const passedHours = Math.floor(passedMinutes / 60);
5789
5811
  if (passedHours < 24) {
5790
- return `${passedHours} hour${passedHours > 1 ? "s" : ""} ago`;
5812
+ return `${passedHours} hour${passedHours > 1 ? "s" : ""} ${tense}`;
5791
5813
  }
5792
5814
  const passedDays = Math.floor(passedHours / 24);
5793
5815
  if (passedDays < 30) {
5794
- return `${passedDays} day${passedDays > 1 ? "s" : ""} ago`;
5816
+ return `${passedDays} day${passedDays > 1 ? "s" : ""} ${tense}`;
5795
5817
  }
5796
5818
  const passedMonths = Math.floor(passedDays / 30);
5797
5819
  if (passedMonths < 12) {
5798
- return `${passedMonths} month${passedMonths > 1 ? "s" : ""} ago`;
5820
+ return `${passedMonths} month${passedMonths > 1 ? "s" : ""} ${tense}`;
5799
5821
  }
5800
5822
  const passedYears = Math.floor(passedMonths / 12);
5801
- return `${passedYears} year${passedYears > 1 ? "s" : ""} ago`;
5823
+ return `${passedYears} year${passedYears > 1 ? "s" : ""} ${tense}`;
5802
5824
  }
5803
5825
  UTC.GetPassedTime = GetPassedTime;
5804
5826
  /**
@@ -5879,7 +5901,13 @@
5879
5901
  * @param value
5880
5902
  */
5881
5903
  Set(key, value) {
5882
- 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) {
5883
5911
  const leastRecentlyUsedKey = this.cache.keys().next().value;
5884
5912
  this.cache.delete(leastRecentlyUsedKey);
5885
5913
  }
@@ -7589,15 +7617,15 @@
7589
7617
  * @returns
7590
7618
  */
7591
7619
  function Round(num, decimals = 0) {
7592
- if (decimals <= 0) {
7593
- return Math.round(num);
7620
+ const n = typeof num === 'string' ? parseFloat(num) : num;
7621
+ if (isNaN(n)) {
7622
+ return 0;
7594
7623
  }
7595
- let tmp = "1";
7596
- for (let i = 0; i < decimals; i++) {
7597
- tmp += "0";
7624
+ if (decimals <= 0) {
7625
+ return Math.round(n);
7598
7626
  }
7599
- const d = parseFloat(tmp);
7600
- return Math.round((num + Number.EPSILON) * d) / d;
7627
+ const multiplier = Math.pow(10, decimals);
7628
+ return Math.round((n + Number.EPSILON) * multiplier) / multiplier;
7601
7629
  }
7602
7630
  MathUtils.Round = Round;
7603
7631
  /**
@@ -15340,7 +15368,7 @@
15340
15368
  })(exports.Scenario || (exports.Scenario = {}));
15341
15369
 
15342
15370
  // This is updated with the package.json version on build.
15343
- const VERSION = "5.9.7";
15371
+ const VERSION = "5.9.8";
15344
15372
 
15345
15373
  exports.VERSION = VERSION;
15346
15374
  exports.AbstractApi = AbstractApi;