@dra2020/baseclient 1.0.143 → 1.0.144

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.
@@ -1244,12 +1244,17 @@ var __importStar = (this && this.__importStar) || function (mod) {
1244
1244
  Object.defineProperty(exports, "__esModule", ({ value: true }));
1245
1245
  exports.FormatDetail = void 0;
1246
1246
  const Util = __importStar(__webpack_require__(/*! ../util/all */ "./lib/util/all.ts"));
1247
+ //import { Util } from '@dra2020/baseclient';
1247
1248
  const reIdentifier = /\b[a-zA-Z_$][a-zA-Z0-9_$]*\b/g;
1249
+ const reIdentifierOrString = /([a-zA-Z_$][a-zA-Z0-9_$]*)|(['"])(?:(?=(\\?))\3.)*?\2/g;
1248
1250
  const reParam = /^__\d+$/;
1251
+ const reString = /^['"]/;
1249
1252
  // Number format: (locale|general|integer|currency).precision
1250
1253
  function formatNumber(n, format) {
1251
1254
  if (!format)
1252
1255
  format = 'locale.0';
1256
+ if (isNaN(n))
1257
+ n = 0;
1253
1258
  let parts = format.split('.');
1254
1259
  let fmt = parts[0];
1255
1260
  let precision = Number(parts[1] || '0');
@@ -1258,7 +1263,8 @@ function formatNumber(n, format) {
1258
1263
  }
1259
1264
  const DefaultDetailOptions = { numberFormat: 'locale.0' };
1260
1265
  class Evaluator {
1261
- constructor(expr) {
1266
+ constructor(expr, options) {
1267
+ this.options = Util.shallowAssignImmutable(DefaultDetailOptions, options);
1262
1268
  this.expr = expr;
1263
1269
  this._error = false;
1264
1270
  }
@@ -1277,15 +1283,20 @@ class Evaluator {
1277
1283
  let values = Object.values(o);
1278
1284
  let safeexpr = this.expr;
1279
1285
  let safenames = names.map(n => namemap[n]);
1280
- // replace longest field names first in case they contain substrings of short field names
1281
- names.sort((n1, n2) => n2.length - n1.length);
1282
- names.forEach((n, i) => {
1283
- while (safeexpr.indexOf(n) >= 0)
1284
- safeexpr = safeexpr.replace(n, namemap[n]);
1286
+ // Replace valid identifiers with safe version
1287
+ safeexpr = safeexpr.replace(reIdentifierOrString, (match) => {
1288
+ if (namemap[match])
1289
+ return namemap[match];
1290
+ else if (match === '__format' || reString.test(match))
1291
+ return match;
1292
+ else {
1293
+ this._error = true;
1294
+ return 'invalid';
1295
+ }
1285
1296
  });
1286
1297
  // Remove any identifiers that aren't the simple parameters to prevent out-of-sandbox execution
1287
- safeexpr = safeexpr.replace(reIdentifier, (match) => {
1288
- let valid = reParam.test(match);
1298
+ safeexpr = safeexpr.replace(reIdentifierOrString, (match) => {
1299
+ let valid = reParam.test(match) || match === '__format' || reString.test(match);
1289
1300
  if (valid)
1290
1301
  return match;
1291
1302
  else {
@@ -1293,12 +1304,15 @@ class Evaluator {
1293
1304
  return 'invalid';
1294
1305
  }
1295
1306
  });
1307
+ let __format = (n) => { return formatNumber(n, this.options.numberFormat); };
1308
+ safenames.push('__format');
1309
+ values.push(__format);
1296
1310
  // Create a new function that accepts the variables as parameters
1297
1311
  // and evaluates the expression
1298
1312
  const func = new Function(...safenames, `return ${safeexpr};`);
1299
1313
  // Call the function with the variable values
1300
1314
  let r = func(...values);
1301
- return isNaN(r) ? 0 : r;
1315
+ return typeof r === 'string' ? r : ((typeof r !== 'number' || isNaN(r)) ? 0 : r);
1302
1316
  }
1303
1317
  catch (err) {
1304
1318
  this._error = true;
@@ -1315,28 +1329,8 @@ class FormatDetail {
1315
1329
  this.pattern = pattern.trim();
1316
1330
  let a = reExpr.exec(pattern);
1317
1331
  if (a && a.length == 2) {
1318
- this.items = [];
1319
1332
  const expr = a[1];
1320
- const parse = expr.split('"');
1321
- let state = 'expr';
1322
- parse.forEach(subexpr => {
1323
- if (state === 'expr') {
1324
- if (subexpr.length) {
1325
- // Don't allow unsafe actions
1326
- if (reInvalidChars.test(subexpr))
1327
- this.items.push({ text: subexpr });
1328
- else
1329
- this.items.push({ expr: subexpr });
1330
- }
1331
- state = 'text';
1332
- }
1333
- else // state === 'text'
1334
- {
1335
- if (subexpr.length)
1336
- this.items.push({ text: subexpr });
1337
- state = 'expr';
1338
- }
1339
- });
1333
+ this.items = [{ expr }];
1340
1334
  }
1341
1335
  else {
1342
1336
  this._error = true;
@@ -1364,16 +1358,19 @@ class FormatDetail {
1364
1358
  this._error = true;
1365
1359
  return { n: 0, v: '' };
1366
1360
  }
1367
- let n;
1361
+ let n = 0;
1368
1362
  let av = this.items.map(di => {
1369
1363
  if (di.text)
1370
1364
  return di.text;
1371
1365
  else {
1372
- let e = new Evaluator(di.expr);
1366
+ let e = new Evaluator(di.expr, this.options);
1373
1367
  n = e.eval(o);
1374
1368
  if (!this._error)
1375
1369
  this._error = e.error;
1376
- return formatNumber(n, this.options.numberFormat);
1370
+ if (typeof n === 'string')
1371
+ return n;
1372
+ else
1373
+ return formatNumber(n, this.options.numberFormat);
1377
1374
  }
1378
1375
  });
1379
1376
  return { n, v: av.join('') };