@dra2020/baseclient 1.0.128 → 1.0.130

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.
@@ -0,0 +1 @@
1
+ export * from './detail';
@@ -0,0 +1,22 @@
1
+ interface DetailItem {
2
+ expr?: string;
3
+ text?: string;
4
+ }
5
+ interface DetailLine {
6
+ label: string;
7
+ items: DetailItem[];
8
+ }
9
+ export interface DetailResult {
10
+ k: string;
11
+ n: number;
12
+ v: string;
13
+ t?: string;
14
+ }
15
+ export declare class FormatDetail {
16
+ valid: boolean;
17
+ pattern: string;
18
+ lines: DetailLine[];
19
+ constructor(pattern: string);
20
+ format(o: any): DetailResult[];
21
+ }
22
+ export {};
@@ -24,6 +24,8 @@ export declare const FilterCOI: number;
24
24
  export declare const FilterMyGroupMaps: number;
25
25
  export declare const FilterMyGroups: number;
26
26
  export declare const FilterMyDatasets: number;
27
+ export declare const FilterPublicDatasets: number;
28
+ export declare const FilterMyGroupDatasets: number;
27
29
  export declare const FilterCount: number;
28
30
  export declare type Filter = number;
29
31
  export declare const PermNone: number;
package/lib/all/all.ts CHANGED
@@ -27,3 +27,5 @@ import * as Colors from '../colors/colors';
27
27
  export { Colors };
28
28
  import * as DataFlow from '../dataflow/all';
29
29
  export { DataFlow }
30
+ import * as Detail from '../detail/all';
31
+ export { Detail }
@@ -0,0 +1 @@
1
+ export * from './detail';
@@ -0,0 +1,173 @@
1
+ //
2
+ // FormatDetail will take a pattern that specifies a set of formatted detail lines.
3
+ // Given an object with a set of integer properties, it will evaluate the pattern and produce
4
+ // an array of { k: string, n: number, v: string } results for displaying the contents of the object.
5
+ //
6
+ // The formatting string contains a series of statements, separated by newline or semicolon.
7
+ // A single statement is of the form:
8
+ // label=expr
9
+ // Expr can be an arithmetic expression using +-/*() as operators and variables are the field
10
+ // names of properties on the object passed in. The special field name _tot represents the
11
+ // total of all properties. The expression may also include double-quoted strings that are
12
+ // passed through (e.g. for use as labels = area" sqm")
13
+ //
14
+
15
+ import * as Util from '../util/all';
16
+
17
+ const reIdentifier = /\b[a-zA-Z_$][a-zA-Z0-9_$]*\b/g;
18
+ const reParam = /^__\d+$/
19
+
20
+ class Evaluator
21
+ {
22
+ expr: string;
23
+
24
+ constructor(expr: string)
25
+ {
26
+ this.expr = expr;
27
+ }
28
+
29
+ eval(o: any): number
30
+ {
31
+ try
32
+ {
33
+ // Convert property names to valid Javascript to ensure expression safety
34
+ o = Util.shallowCopy(o);
35
+ let namemap: any = {};
36
+ Object.keys(o).forEach((n: string, i: number) => {
37
+ namemap[n] = `__${i}`;
38
+ });
39
+
40
+ // Extract variable names and values from the object
41
+ let names = Object.keys(o);
42
+ let values = Object.values(o);
43
+ let safeexpr = this.expr;
44
+ let safenames = names.map(n => namemap[n]);
45
+ // replace longest field names first in case they contain substrings of short field names
46
+ names.sort((n1: string, n2: string) => n2.length - n1.length);
47
+ names.forEach((n: string, i: number) => {
48
+ while (safeexpr.indexOf(n) >= 0)
49
+ safeexpr = safeexpr.replace(n, namemap[n]);
50
+ });
51
+
52
+ // Remove any identifiers that aren't the simple parameters to prevent out-of-sandbox execution
53
+ safeexpr = safeexpr.replace(reIdentifier, (match) => { return reParam.test(match) ? match : "invalid" });
54
+
55
+ // Create a new function that accepts the variables as parameters
56
+ // and evaluates the expression
57
+ const func = new Function(...safenames, `return ${safeexpr};`);
58
+
59
+ // Call the function with the variable values
60
+ let r = func(...values);
61
+ return isNaN(r) ? 0 : r;
62
+ }
63
+ catch (err)
64
+ {
65
+ return 0;
66
+ }
67
+ }
68
+ }
69
+
70
+ interface DetailItem
71
+ {
72
+ expr?: string,
73
+ text?: string,
74
+ }
75
+
76
+ interface DetailLine
77
+ {
78
+ label: string,
79
+ items: DetailItem[],
80
+ }
81
+
82
+ export interface DetailResult
83
+ {
84
+ k: string, // label
85
+ n: number, // value before formatting
86
+ v: string, // value
87
+ t?: string, // tooltip
88
+ }
89
+
90
+ const reInvalidChars = /[\.\[\]\\]/;
91
+
92
+ export class FormatDetail
93
+ {
94
+ valid: boolean;
95
+ pattern: string;
96
+ lines: DetailLine[];
97
+
98
+ constructor(pattern: string)
99
+ {
100
+ this.valid = true;
101
+ this.pattern = pattern;
102
+ this.lines = [];
103
+ let lines = this.pattern.split(/[;\n]/).map(l => l.trim()).filter(l => !!l);
104
+ lines.forEach(line => {
105
+ let sides = line.split('=').map(l => l.trim()).filter(l => !!l);
106
+ if (sides.length != 2)
107
+ this.valid = false;
108
+ else
109
+ {
110
+ const lhs = sides[0];
111
+ const rhs = sides[1];
112
+ let parse = rhs.split('"');
113
+ let items: DetailItem[] = [];
114
+ let state = 'expr';
115
+ parse.forEach(subexpr => {
116
+ if (state === 'expr')
117
+ {
118
+ if (subexpr.length)
119
+ {
120
+ // Don't allow unsafe actions
121
+ if (reInvalidChars.test(subexpr))
122
+ items.push({ text: subexpr });
123
+ else
124
+ items.push({ expr: subexpr });
125
+ }
126
+ state = 'text';
127
+ }
128
+ else // state === 'text'
129
+ {
130
+ if (subexpr.length)
131
+ items.push({ text: subexpr });
132
+ state = 'expr';
133
+ }
134
+ });
135
+ this.lines.push( { label: lhs, items } );
136
+ }
137
+ });
138
+ }
139
+
140
+ format(o: any): DetailResult[]
141
+ {
142
+ if (!o) return [];
143
+ // Make sure there is a total field
144
+ o = Util.deepCopy(o);
145
+ if (o['Tot'] !== undefined)
146
+ o['_tot'] = o['Tot'];
147
+ else
148
+ {
149
+ let t = 0;
150
+ Object.values(o).forEach((v: any) => {
151
+ if (!isNaN(v) && typeof v === 'number')
152
+ t += v;
153
+ });
154
+ o['_tot'] = t;
155
+ }
156
+ let result: DetailResult[] = [];
157
+ this.lines.forEach(line => {
158
+ let n: number;
159
+ let av = line.items.map(di => {
160
+ if (di.text)
161
+ return di.text;
162
+ else
163
+ {
164
+ let e = new Evaluator(di.expr);
165
+ n = e.eval(o);
166
+ return Util.precisionRound(n, 0).toLocaleString();
167
+ }
168
+ });
169
+ result.push({ k: line.label, n, v: av.join('') });
170
+ });
171
+ return result;
172
+ }
173
+ }
@@ -27,7 +27,9 @@ export const FilterCOI: number = 7;
27
27
  export const FilterMyGroupMaps: number = 8;
28
28
  export const FilterMyGroups: number = 9;
29
29
  export const FilterMyDatasets: number = 10;
30
- export const FilterCount: number = 11;
30
+ export const FilterPublicDatasets: number = 11;
31
+ export const FilterMyGroupDatasets: number = 12;
32
+ export const FilterCount: number = 13;
31
33
  export type Filter = number;
32
34
 
33
35
  // Permissions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dra2020/baseclient",
3
- "version": "1.0.128",
3
+ "version": "1.0.130",
4
4
  "description": "Utility functions for Javascript projects.",
5
5
  "main": "dist/baseclient.js",
6
6
  "types": "./dist/all/all.d.ts",