@dra2020/baseclient 1.0.143 → 1.0.145

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.
@@ -22,5 +22,6 @@ export declare class MultiBlockMapping {
22
22
  mapmain(blockid: string): string;
23
23
  rev(geoid: string): string[];
24
24
  forEach(cb: (blockid: string) => void): void;
25
+ forEachRev(cb: (geoidid: string, blocks: string[]) => void): void;
25
26
  }
26
27
  export {};
@@ -12,15 +12,19 @@
12
12
  //
13
13
 
14
14
  import * as Util from '../util/all';
15
+ //import { Util } from '@dra2020/baseclient';
15
16
 
16
17
  const reIdentifier = /\b[a-zA-Z_$][a-zA-Z0-9_$]*\b/g;
17
- const reParam = /^__\d+$/
18
+ const reIdentifierOrString = /([a-zA-Z_$][a-zA-Z0-9_$]*)|(['"])(?:(?=(\\?))\3.)*?\2/g;
19
+ const reParam = /^__\d+$/;
20
+ const reString = /^['"]/;
18
21
 
19
22
  // Number format: (locale|general|integer|currency).precision
20
23
 
21
24
  function formatNumber(n: number, format: string): string
22
25
  {
23
26
  if (!format) format = 'locale.0';
27
+ if (isNaN(n)) n = 0;
24
28
  let parts = format.split('.');
25
29
  let fmt = parts[0];
26
30
  let precision = Number(parts[1] || '0');
@@ -37,18 +41,20 @@ const DefaultDetailOptions: DetailOptions = { numberFormat: 'locale.0' };
37
41
 
38
42
  class Evaluator
39
43
  {
44
+ options: DetailOptions;
40
45
  expr: string;
41
46
  _error: boolean;
42
47
 
43
- constructor(expr: string)
48
+ constructor(expr: string, options?: DetailOptions)
44
49
  {
50
+ this.options = Util.shallowAssignImmutable(DefaultDetailOptions, options);
45
51
  this.expr = expr;
46
52
  this._error = false;
47
53
  }
48
54
 
49
55
  get error(): boolean { return this._error }
50
56
 
51
- eval(o: any): number
57
+ eval(o: any): any
52
58
  {
53
59
  this._error = false;
54
60
  try
@@ -65,17 +71,25 @@ class Evaluator
65
71
  let values = Object.values(o);
66
72
  let safeexpr = this.expr;
67
73
  let safenames = names.map(n => namemap[n]);
68
- // replace longest field names first in case they contain substrings of short field names
69
- names.sort((n1: string, n2: string) => n2.length - n1.length);
70
- names.forEach((n: string, i: number) => {
71
- while (safeexpr.indexOf(n) >= 0)
72
- safeexpr = safeexpr.replace(n, namemap[n]);
73
- });
74
+
75
+ // Replace valid identifiers with safe version
76
+ safeexpr = safeexpr.replace(reIdentifierOrString,
77
+ (match) => {
78
+ if (namemap[match])
79
+ return namemap[match];
80
+ else if (match === '__format' || reString.test(match))
81
+ return match;
82
+ else
83
+ {
84
+ this._error = true;
85
+ return 'invalid';
86
+ }
87
+ });
74
88
 
75
89
  // Remove any identifiers that aren't the simple parameters to prevent out-of-sandbox execution
76
- safeexpr = safeexpr.replace(reIdentifier,
90
+ safeexpr = safeexpr.replace(reIdentifierOrString,
77
91
  (match) => {
78
- let valid = reParam.test(match);
92
+ let valid = reParam.test(match) || match === '__format' || reString.test(match);
79
93
  if (valid)
80
94
  return match;
81
95
  else
@@ -84,6 +98,9 @@ class Evaluator
84
98
  return 'invalid';
85
99
  }
86
100
  });
101
+ let __format = (n: number) => { return formatNumber(n, this.options.numberFormat) };
102
+ safenames.push('__format');
103
+ values.push(__format);
87
104
 
88
105
  // Create a new function that accepts the variables as parameters
89
106
  // and evaluates the expression
@@ -91,7 +108,7 @@ class Evaluator
91
108
 
92
109
  // Call the function with the variable values
93
110
  let r = func(...values);
94
- return isNaN(r) ? 0 : r;
111
+ return typeof r === 'string' ? r : ((typeof r !== 'number' || isNaN(r)) ? 0 : r);
95
112
  }
96
113
  catch (err)
97
114
  {
@@ -131,30 +148,8 @@ export class FormatDetail
131
148
  let a = reExpr.exec(pattern);
132
149
  if (a && a.length == 2)
133
150
  {
134
- this.items = [];
135
151
  const expr = a[1];
136
- const parse = expr.split('"');
137
- let state = 'expr';
138
- parse.forEach(subexpr => {
139
- if (state === 'expr')
140
- {
141
- if (subexpr.length)
142
- {
143
- // Don't allow unsafe actions
144
- if (reInvalidChars.test(subexpr))
145
- this.items.push({ text: subexpr });
146
- else
147
- this.items.push({ expr: subexpr });
148
- }
149
- state = 'text';
150
- }
151
- else // state === 'text'
152
- {
153
- if (subexpr.length)
154
- this.items.push({ text: subexpr });
155
- state = 'expr';
156
- }
157
- });
152
+ this.items = [ { expr } ];
158
153
  }
159
154
  else
160
155
  {
@@ -191,17 +186,20 @@ export class FormatDetail
191
186
  this._error = true;
192
187
  return { n: 0, v: '' };
193
188
  }
194
- let n: number;
189
+ let n: any = 0;
195
190
  let av = this.items.map(di => {
196
191
  if (di.text)
197
192
  return di.text;
198
193
  else
199
194
  {
200
- let e = new Evaluator(di.expr);
195
+ let e = new Evaluator(di.expr, this.options);
201
196
  n = e.eval(o);
202
197
  if (! this._error)
203
198
  this._error = e.error;
204
- return formatNumber(n, this.options.numberFormat);
199
+ if (typeof n === 'string')
200
+ return n;
201
+ else
202
+ return formatNumber(n, this.options.numberFormat);
205
203
  }
206
204
  });
207
205
  return { n, v: av.join('') }
@@ -101,4 +101,15 @@ export class MultiBlockMapping
101
101
  if (this.entries.length)
102
102
  Object.keys(this.entries[0].bm).forEach(blockid => cb(blockid));
103
103
  }
104
+
105
+ // Just walks first map
106
+ forEachRev(cb: (geoidid: string, blocks: string[]) => void): void
107
+ {
108
+ for (let i = 0; i < this.entries.length; i++)
109
+ {
110
+ let e = this.entries[i];
111
+ if (! e.rbm) e.rbm = reverseBlockMapping(e.bm);
112
+ Object.keys(e.rbm).forEach(geoid => cb(geoid, e.rbm[geoid]));
113
+ }
114
+ }
104
115
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dra2020/baseclient",
3
- "version": "1.0.143",
3
+ "version": "1.0.145",
4
4
  "description": "Utility functions for Javascript projects.",
5
5
  "main": "dist/baseclient.js",
6
6
  "types": "./dist/all/all.d.ts",