bruce-models 5.9.7 → 5.9.9

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 (40) hide show
  1. package/dist/bruce-models.es5.js +144 -103
  2. package/dist/bruce-models.es5.js.map +1 -1
  3. package/dist/bruce-models.umd.js +144 -103
  4. package/dist/bruce-models.umd.js.map +1 -1
  5. package/dist/lib/api/api.js.map +1 -1
  6. package/dist/lib/assembly/assembly.js +16 -3
  7. package/dist/lib/assembly/assembly.js.map +1 -1
  8. package/dist/lib/bruce-models.js +1 -1
  9. package/dist/lib/calculator/calculator.js +25 -13
  10. package/dist/lib/calculator/calculator.js.map +1 -1
  11. package/dist/lib/common/bruce-event.js +8 -3
  12. package/dist/lib/common/bruce-event.js.map +1 -1
  13. package/dist/lib/common/bruce-variable.js +31 -38
  14. package/dist/lib/common/bruce-variable.js.map +1 -1
  15. package/dist/lib/common/cache.js +2 -3
  16. package/dist/lib/common/cache.js.map +1 -1
  17. package/dist/lib/common/delay-queue.js +6 -2
  18. package/dist/lib/common/delay-queue.js.map +1 -1
  19. package/dist/lib/common/geometry.js +17 -13
  20. package/dist/lib/common/geometry.js.map +1 -1
  21. package/dist/lib/common/lru-cache.js +7 -1
  22. package/dist/lib/common/lru-cache.js.map +1 -1
  23. package/dist/lib/common/utc.js +15 -7
  24. package/dist/lib/common/utc.js.map +1 -1
  25. package/dist/lib/entity/entity-attribute.js +4 -1
  26. package/dist/lib/entity/entity-attribute.js.map +1 -1
  27. package/dist/lib/entity/entity.js +1 -1
  28. package/dist/lib/entity/entity.js.map +1 -1
  29. package/dist/lib/util/math-utils.js +7 -7
  30. package/dist/lib/util/math-utils.js.map +1 -1
  31. package/dist/lib/util/path-utils.js +6 -5
  32. package/dist/lib/util/path-utils.js.map +1 -1
  33. package/dist/types/api/api.d.ts +2 -2
  34. package/dist/types/assembly/assembly.d.ts +8 -2
  35. package/dist/types/bruce-models.d.ts +1 -1
  36. package/dist/types/calculator/calculator.d.ts +1 -1
  37. package/dist/types/common/bruce-variable.d.ts +1 -0
  38. package/dist/types/common/delay-queue.d.ts +2 -1
  39. package/dist/types/util/math-utils.d.ts +1 -1
  40. 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
  }
@@ -1860,8 +1863,11 @@
1860
1863
  if (!api) {
1861
1864
  api = exports.ENVIRONMENT.Api().GetBruceApi();
1862
1865
  }
1863
- yield api.DELETE(`v3/assembly/${assemblyId}`, exports.Api.PrepReqParams(reqParams));
1866
+ const res = yield api.DELETE(`v3/assembly/${assemblyId}`, exports.Api.PrepReqParams(reqParams));
1864
1867
  api.Cache.RemoveByStartsWith(exports.Api.ECacheKey.Assembly + exports.Api.ECacheKey.Id + assemblyId);
1868
+ return {
1869
+ action: res
1870
+ };
1865
1871
  });
1866
1872
  }
1867
1873
  Assembly.Delete = Delete;
@@ -1871,7 +1877,7 @@
1871
1877
  */
1872
1878
  function DeleteList(params) {
1873
1879
  return __awaiter(this, void 0, void 0, function* () {
1874
- let { api, req: reqParams } = params;
1880
+ let { api, req: reqParams, assemblyIds } = params;
1875
1881
  if (!api) {
1876
1882
  api = exports.ENVIRONMENT.Api().GetBruceApi();
1877
1883
  }
@@ -1880,9 +1886,19 @@
1880
1886
  if (params.invalidRootIds) {
1881
1887
  urlParams.append("InvalidRootEntityID", "true");
1882
1888
  }
1889
+ // Cannot be used with invalidRootIds.
1890
+ // So if both are supplied, invalidRootIds will take precedence.
1891
+ else if (params.assemblyIds) {
1892
+ for (let i = 0; i < assemblyIds.length; i++) {
1893
+ urlParams.append("ID", String(assemblyIds[i]));
1894
+ }
1895
+ }
1883
1896
  url += "?" + urlParams.toString();
1884
- yield api.DELETE(url, exports.Api.PrepReqParams(reqParams));
1897
+ const res = yield api.DELETE(url, exports.Api.PrepReqParams(reqParams));
1885
1898
  api.Cache.RemoveByStartsWith(exports.Api.ECacheKey.Assembly);
1899
+ return {
1900
+ action: res
1901
+ };
1886
1902
  });
1887
1903
  }
1888
1904
  Assembly.DeleteList = DeleteList;
@@ -2544,7 +2560,10 @@
2544
2560
  }
2545
2561
  const key = path[0];
2546
2562
  const item = items.find((i) => i.Key === key);
2547
- if (!item || !item.Structure || !path.length) {
2563
+ if (!item) {
2564
+ return null;
2565
+ }
2566
+ if (path.length === 1) {
2548
2567
  return item;
2549
2568
  }
2550
2569
  return GetAttribute(item.Structure, path.slice(1));
@@ -3128,13 +3147,14 @@
3128
3147
  }
3129
3148
  const broken = str.split(".");
3130
3149
  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);
3150
+ let piece = broken[i];
3151
+ if (piece.startsWith("\"")) {
3152
+ piece = piece.substring(1);
3134
3153
  }
3135
- if (piece.charAt(piece.length - 1) == "\"") {
3136
- broken[0] = piece.substring(0, piece.length - 1);
3154
+ if (piece.endsWith("\"")) {
3155
+ piece = piece.substring(0, piece.length - 1);
3137
3156
  }
3157
+ broken[i] = piece;
3138
3158
  }
3139
3159
  return broken;
3140
3160
  }
@@ -3792,7 +3812,7 @@
3792
3812
  function GetValue(params) {
3793
3813
  var _a;
3794
3814
  let { entity: data, path, handleLegacy: checkAgainstLegacy } = params;
3795
- if (checkAgainstLegacy == null) {
3815
+ if (checkAgainstLegacy == null || checkAgainstLegacy == undefined) {
3796
3816
  checkAgainstLegacy = true;
3797
3817
  }
3798
3818
  if (!path || !path.length) {
@@ -4337,25 +4357,6 @@
4337
4357
  Entity.GetHistoricContainsKey = GetHistoricContainsKey;
4338
4358
  })(exports.Entity || (exports.Entity = {}));
4339
4359
 
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
4360
  (function (BruceVariable) {
4360
4361
  /**
4361
4362
  * Replaces all Bruce variables in a string with the value of the attribute.
@@ -4365,28 +4366,40 @@
4365
4366
  * @returns
4366
4367
  */
4367
4368
  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);
4369
+ const { str, entity: data, legacyParse, retainType } = params;
4370
+ // If the input is just a path, return the value of the path.
4371
+ // We only do this for 'retainType=true' because all existing code expects a string result.
4372
+ if (retainType && str.startsWith("${") && str.endsWith("}")) {
4373
+ let pathStr = str.slice(2, -1);
4374
+ pathStr = pathStr.trim();
4375
+ const path = legacyParse ? exports.PathUtils.ParseLegacy(pathStr) : exports.PathUtils.Parse(pathStr);
4376
+ return exports.Entity.GetValue({
4377
+ entity: data,
4378
+ path: path
4379
+ });
4380
+ }
4381
+ // Regex that will match all Bruce variables.
4382
+ // It looks for ${...} and captures the content inside the brackets.
4383
+ const variableRegex = /\${([^}]*)}/g;
4384
+ return str.replace(variableRegex, (match, pathStr) => {
4385
+ // If the path is empty or just whitespace, return empty string
4386
+ if (!pathStr || pathStr.trim().length === 0) {
4387
+ return "";
4384
4388
  }
4385
- else {
4386
- break;
4389
+ pathStr = pathStr.trim();
4390
+ const path = legacyParse ? exports.PathUtils.ParseLegacy(pathStr) : exports.PathUtils.Parse(pathStr);
4391
+ if (!path.length) {
4392
+ return "";
4387
4393
  }
4388
- }
4389
- return str;
4394
+ const value = exports.Entity.GetValue({
4395
+ entity: data,
4396
+ path: path
4397
+ });
4398
+ if (value == null || value == undefined) {
4399
+ return "";
4400
+ }
4401
+ return String(value);
4402
+ });
4390
4403
  }
4391
4404
  BruceVariable.SwapValues = SwapValues;
4392
4405
  })(exports.BruceVariable || (exports.BruceVariable = {}));
@@ -4465,6 +4478,11 @@
4465
4478
  */
4466
4479
  function Calculate(params) {
4467
4480
  let { fields, tags, data, defaultValue, type } = params;
4481
+ // If params doesn't include a defaultValue, use null.
4482
+ // Though passing in undefined is valid!
4483
+ if ("defaultValue" in params == false) {
4484
+ defaultValue = null;
4485
+ }
4468
4486
  if (fields == null) {
4469
4487
  return defaultValue;
4470
4488
  }
@@ -4515,11 +4533,6 @@
4515
4533
  let value = null;
4516
4534
  for (let i = 0; i < fieldsArr.length; i++) {
4517
4535
  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
4536
  // Bad data has it set to 'color' but expects the input to be a number.
4524
4537
  if (type == "number" && field.type == EValueType.Color) {
4525
4538
  field.type = EValueType.Input;
@@ -4876,20 +4889,26 @@
4876
4889
  try {
4877
4890
  value = exports.BruceVariable.SwapValues({
4878
4891
  str: value,
4879
- entity: entity
4892
+ entity: entity,
4893
+ retainType: true
4880
4894
  });
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();
4895
+ if (value == null || value == undefined) {
4896
+ return null;
4897
+ }
4898
+ if (typeof value === "string") {
4899
+ const isJsEval = value.startsWith("JS:");
4900
+ const MATH_REGEX = /(\d+\.?\d*|\.\d+)([+\-*/])(\d+\.?\d*|\.\d+)/;
4901
+ const isMathEval = isJsEval || MATH_REGEX.test(value);
4902
+ if (isJsEval || isMathEval) {
4903
+ if (isJsEval) {
4904
+ value = value.replace("JS:", "");
4905
+ value = value.trim();
4906
+ }
4907
+ // https://rollupjs.org/guide/en/#avoiding-eval
4908
+ // This stops eval warning.
4909
+ const eval2 = eval;
4910
+ return eval2(value);
4888
4911
  }
4889
- // https://rollupjs.org/guide/en/#avoiding-eval
4890
- // This stops eval warning.
4891
- const eval2 = eval;
4892
- return eval2(value);
4893
4912
  }
4894
4913
  }
4895
4914
  catch (exception) {
@@ -4943,13 +4962,7 @@
4943
4962
  if (!points.length) {
4944
4963
  throw ("points is empty.");
4945
4964
  }
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;
4965
+ return points.map(carto => `${carto.longitude},${carto.latitude}` + (carto.altitude != null ? `,${carto.altitude}` : "")).join(' ');
4953
4966
  }
4954
4967
  Geometry.LineStrFromPoints = LineStrFromPoints;
4955
4968
  /**
@@ -5041,6 +5054,9 @@
5041
5054
  }
5042
5055
  return newGeometry;
5043
5056
  }
5057
+ else if (!geometry) {
5058
+ return {};
5059
+ }
5044
5060
  return geometry;
5045
5061
  }
5046
5062
  Geometry.ParseGeometry = ParseGeometry;
@@ -5057,19 +5073,26 @@
5057
5073
  const collection = [];
5058
5074
  // Returns if two coordinates are equal.
5059
5075
  const areCoordinatesEqual = (coord1, coord2) => {
5060
- return coord1[0] === coord2[0] && coord1[1] === coord2[1] && coord1[2] === coord2[2];
5076
+ return coord1[0] === coord2[0] && coord1[1] === coord2[1] &&
5077
+ (noAltitude || coord1[2] === coord2[2]);
5061
5078
  };
5062
5079
  // Removes consecutive duplicate coordinates.
5063
5080
  const removeConsecutiveDuplicates = (coordinates) => {
5064
- return coordinates.filter((coord, index) => {
5065
- return index === 0 || !areCoordinatesEqual(coord, coordinates[index - 1]);
5066
- });
5081
+ if (coordinates.length <= 1)
5082
+ return coordinates;
5083
+ const result = [coordinates[0]];
5084
+ for (let i = 1; i < coordinates.length; i++) {
5085
+ if (!areCoordinatesEqual(coordinates[i], coordinates[i - 1])) {
5086
+ result.push(coordinates[i]);
5087
+ }
5088
+ }
5089
+ return result;
5067
5090
  };
5068
5091
  // Ensures that the polygon is closed.
5069
5092
  const closePolygonCoordinates = (coordinates) => {
5070
5093
  return coordinates.map(ring => {
5071
- if (!areCoordinatesEqual(ring[0], ring[ring.length - 1])) {
5072
- ring.push(ring[0]);
5094
+ if (ring.length > 0 && !areCoordinatesEqual(ring[0], ring[ring.length - 1])) {
5095
+ return [...ring, ring[0]];
5073
5096
  }
5074
5097
  return ring;
5075
5098
  });
@@ -5659,13 +5682,14 @@
5659
5682
  * If you have a method that may be called often, but you don't want it to run often, use this.
5660
5683
  */
5661
5684
  class DelayQueue {
5662
- constructor(callback, delay = 200) {
5685
+ constructor(callback, delay = 200, startDelayed = false) {
5663
5686
  // Millisecond delay.
5664
5687
  this.delay = 200;
5665
5688
  // Date-time stamp for the last callback call.
5666
5689
  this.lastCallTime = null;
5667
5690
  this.callback = callback;
5668
5691
  this.delay = delay;
5692
+ this.startDelayed = startDelayed;
5669
5693
  }
5670
5694
  /**
5671
5695
  * Request a call on the callback.
@@ -5673,7 +5697,10 @@
5673
5697
  */
5674
5698
  Call(force = false) {
5675
5699
  if (this.lastCallTime == null) {
5676
- force = true;
5700
+ this.lastCallTime = new Date().getTime();
5701
+ if (this.startDelayed) {
5702
+ force = false;
5703
+ }
5677
5704
  }
5678
5705
  if (force) {
5679
5706
  let endDate = new Date().getTime();
@@ -5777,28 +5804,36 @@
5777
5804
  * @param utc
5778
5805
  */
5779
5806
  function GetPassedTime(utc) {
5780
- const passedSeconds = GetPassedSeconds(utc);
5807
+ let tense = "ago";
5808
+ let passedSeconds = GetPassedSeconds(utc);
5809
+ if (passedSeconds < 0) {
5810
+ // Account for the time difference between the client and the server.
5811
+ if (passedSeconds < -(15 * 60)) {
5812
+ return "recently";
5813
+ }
5814
+ tense = "from now";
5815
+ }
5781
5816
  if (passedSeconds < 60) {
5782
- return `${passedSeconds} second${passedSeconds > 1 ? "s" : ""} ago`;
5817
+ return `${passedSeconds} second${passedSeconds > 1 ? "s" : ""} ${tense}`;
5783
5818
  }
5784
5819
  const passedMinutes = Math.floor(passedSeconds / 60);
5785
5820
  if (passedMinutes < 60) {
5786
- return `${passedMinutes} minute${passedMinutes > 1 ? "s" : ""} ago`;
5821
+ return `${passedMinutes} minute${passedMinutes > 1 ? "s" : ""} ${tense}`;
5787
5822
  }
5788
5823
  const passedHours = Math.floor(passedMinutes / 60);
5789
5824
  if (passedHours < 24) {
5790
- return `${passedHours} hour${passedHours > 1 ? "s" : ""} ago`;
5825
+ return `${passedHours} hour${passedHours > 1 ? "s" : ""} ${tense}`;
5791
5826
  }
5792
5827
  const passedDays = Math.floor(passedHours / 24);
5793
5828
  if (passedDays < 30) {
5794
- return `${passedDays} day${passedDays > 1 ? "s" : ""} ago`;
5829
+ return `${passedDays} day${passedDays > 1 ? "s" : ""} ${tense}`;
5795
5830
  }
5796
5831
  const passedMonths = Math.floor(passedDays / 30);
5797
5832
  if (passedMonths < 12) {
5798
- return `${passedMonths} month${passedMonths > 1 ? "s" : ""} ago`;
5833
+ return `${passedMonths} month${passedMonths > 1 ? "s" : ""} ${tense}`;
5799
5834
  }
5800
5835
  const passedYears = Math.floor(passedMonths / 12);
5801
- return `${passedYears} year${passedYears > 1 ? "s" : ""} ago`;
5836
+ return `${passedYears} year${passedYears > 1 ? "s" : ""} ${tense}`;
5802
5837
  }
5803
5838
  UTC.GetPassedTime = GetPassedTime;
5804
5839
  /**
@@ -5879,7 +5914,13 @@
5879
5914
  * @param value
5880
5915
  */
5881
5916
  Set(key, value) {
5882
- if (this.cache.size >= this.capacity) {
5917
+ if (this.capacity <= 0) {
5918
+ // Empty cache.
5919
+ // Means we were configured to not cache anything.
5920
+ this.cache.clear();
5921
+ return;
5922
+ }
5923
+ else if (this.cache.size >= this.capacity) {
5883
5924
  const leastRecentlyUsedKey = this.cache.keys().next().value;
5884
5925
  this.cache.delete(leastRecentlyUsedKey);
5885
5926
  }
@@ -7589,15 +7630,15 @@
7589
7630
  * @returns
7590
7631
  */
7591
7632
  function Round(num, decimals = 0) {
7592
- if (decimals <= 0) {
7593
- return Math.round(num);
7633
+ const n = typeof num === 'string' ? parseFloat(num) : num;
7634
+ if (isNaN(n)) {
7635
+ return 0;
7594
7636
  }
7595
- let tmp = "1";
7596
- for (let i = 0; i < decimals; i++) {
7597
- tmp += "0";
7637
+ if (decimals <= 0) {
7638
+ return Math.round(n);
7598
7639
  }
7599
- const d = parseFloat(tmp);
7600
- return Math.round((num + Number.EPSILON) * d) / d;
7640
+ const multiplier = Math.pow(10, decimals);
7641
+ return Math.round((n + Number.EPSILON) * multiplier) / multiplier;
7601
7642
  }
7602
7643
  MathUtils.Round = Round;
7603
7644
  /**
@@ -15340,7 +15381,7 @@
15340
15381
  })(exports.Scenario || (exports.Scenario = {}));
15341
15382
 
15342
15383
  // This is updated with the package.json version on build.
15343
- const VERSION = "5.9.7";
15384
+ const VERSION = "5.9.9";
15344
15385
 
15345
15386
  exports.VERSION = VERSION;
15346
15387
  exports.AbstractApi = AbstractApi;