terminusdb 12.0.2
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.
- package/Contributing.md +36 -0
- package/LICENSE +201 -0
- package/README.md +175 -0
- package/RELEASE_NOTES.md +462 -0
- package/dist/index.html +22 -0
- package/dist/terminusdb-client.min.js +3 -0
- package/dist/terminusdb-client.min.js.LICENSE.txt +188 -0
- package/dist/terminusdb-client.min.js.map +1 -0
- package/dist/typescript/index.d.ts +14 -0
- package/dist/typescript/lib/accessControl.d.ts +554 -0
- package/dist/typescript/lib/axiosInstance.d.ts +2 -0
- package/dist/typescript/lib/connectionConfig.d.ts +381 -0
- package/dist/typescript/lib/const.d.ts +54 -0
- package/dist/typescript/lib/dispatchRequest.d.ts +17 -0
- package/dist/typescript/lib/errorMessage.d.ts +25 -0
- package/dist/typescript/lib/query/woqlBuilder.d.ts +75 -0
- package/dist/typescript/lib/query/woqlCore.d.ts +341 -0
- package/dist/typescript/lib/query/woqlDoc.d.ts +63 -0
- package/dist/typescript/lib/query/woqlLibrary.d.ts +718 -0
- package/dist/typescript/lib/query/woqlPrinter.d.ts +71 -0
- package/dist/typescript/lib/query/woqlQuery.d.ts +833 -0
- package/dist/typescript/lib/typedef.d.ts +624 -0
- package/dist/typescript/lib/utils.d.ts +199 -0
- package/dist/typescript/lib/valueHash.d.ts +146 -0
- package/dist/typescript/lib/viewer/chartConfig.d.ts +62 -0
- package/dist/typescript/lib/viewer/chooserConfig.d.ts +38 -0
- package/dist/typescript/lib/viewer/documentFrame.d.ts +44 -0
- package/dist/typescript/lib/viewer/frameConfig.d.ts +74 -0
- package/dist/typescript/lib/viewer/frameRule.d.ts +145 -0
- package/dist/typescript/lib/viewer/graphConfig.d.ts +73 -0
- package/dist/typescript/lib/viewer/objectFrame.d.ts +212 -0
- package/dist/typescript/lib/viewer/streamConfig.d.ts +23 -0
- package/dist/typescript/lib/viewer/tableConfig.d.ts +66 -0
- package/dist/typescript/lib/viewer/terminusRule.d.ts +75 -0
- package/dist/typescript/lib/viewer/viewConfig.d.ts +47 -0
- package/dist/typescript/lib/viewer/woqlChart.d.ts +1 -0
- package/dist/typescript/lib/viewer/woqlChooser.d.ts +56 -0
- package/dist/typescript/lib/viewer/woqlGraph.d.ts +26 -0
- package/dist/typescript/lib/viewer/woqlPaging.d.ts +1 -0
- package/dist/typescript/lib/viewer/woqlResult.d.ts +128 -0
- package/dist/typescript/lib/viewer/woqlRule.d.ts +96 -0
- package/dist/typescript/lib/viewer/woqlStream.d.ts +31 -0
- package/dist/typescript/lib/viewer/woqlTable.d.ts +102 -0
- package/dist/typescript/lib/viewer/woqlView.d.ts +49 -0
- package/dist/typescript/lib/woql.d.ts +1267 -0
- package/dist/typescript/lib/woqlClient.d.ts +1216 -0
- package/index.js +28 -0
- package/lib/.eslintrc +1 -0
- package/lib/accessControl.js +988 -0
- package/lib/axiosInstance.js +5 -0
- package/lib/connectionConfig.js +765 -0
- package/lib/const.js +59 -0
- package/lib/dispatchRequest.js +236 -0
- package/lib/errorMessage.js +110 -0
- package/lib/query/woqlBuilder.js +234 -0
- package/lib/query/woqlCore.js +934 -0
- package/lib/query/woqlDoc.js +177 -0
- package/lib/query/woqlLibrary.js +1015 -0
- package/lib/query/woqlPrinter.js +476 -0
- package/lib/query/woqlQuery.js +1865 -0
- package/lib/typedef.js +248 -0
- package/lib/utils.js +817 -0
- package/lib/valueHash.js_old +581 -0
- package/lib/viewer/chartConfig.js +411 -0
- package/lib/viewer/chooserConfig.js +234 -0
- package/lib/viewer/documentFrame.js +206 -0
- package/lib/viewer/frameConfig.js +469 -0
- package/lib/viewer/frameRule.js +519 -0
- package/lib/viewer/graphConfig.js +345 -0
- package/lib/viewer/objectFrame.js +1550 -0
- package/lib/viewer/streamConfig.js +82 -0
- package/lib/viewer/tableConfig.js +310 -0
- package/lib/viewer/terminusRule.js +196 -0
- package/lib/viewer/viewConfig.js +219 -0
- package/lib/viewer/woqlChart.js +17 -0
- package/lib/viewer/woqlChooser.js +171 -0
- package/lib/viewer/woqlGraph.js +295 -0
- package/lib/viewer/woqlPaging.js +148 -0
- package/lib/viewer/woqlResult.js +258 -0
- package/lib/viewer/woqlRule.js +312 -0
- package/lib/viewer/woqlStream.js +27 -0
- package/lib/viewer/woqlTable.js +332 -0
- package/lib/viewer/woqlView.js +107 -0
- package/lib/woql.js +1693 -0
- package/lib/woqlClient.js +2091 -0
- package/package.json +110 -0
package/lib/utils.js
ADDED
|
@@ -0,0 +1,817 @@
|
|
|
1
|
+
/* eslint-disable no-undef */
|
|
2
|
+
/* eslint-disable guard-for-in */
|
|
3
|
+
/* eslint-disable no-plusplus */
|
|
4
|
+
/* eslint-disable no-shadow */
|
|
5
|
+
/* eslint-disable camelcase */
|
|
6
|
+
/* eslint-disable no-restricted-syntax */
|
|
7
|
+
/* eslint-disable no-param-reassign */
|
|
8
|
+
/**
|
|
9
|
+
* @file Terminus Client Utility Functions
|
|
10
|
+
* @license Apache Version 2
|
|
11
|
+
* Object for bunding up common Terminus Utility Functions
|
|
12
|
+
*/
|
|
13
|
+
const Utils = {};
|
|
14
|
+
|
|
15
|
+
Utils.checkValidName = function (str) {
|
|
16
|
+
if (typeof str !== 'string' || str.trim() === '') return false;
|
|
17
|
+
return /^[a-zA-Z0-9_]*$/.test(str);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
Utils.ACTIONS = {
|
|
21
|
+
CREATE_DATABASE: 'create_database',
|
|
22
|
+
DELETE_DATABASE: 'delete_database',
|
|
23
|
+
SCHEMA_READ_ACCESS: 'schema_read_access',
|
|
24
|
+
SCHEMA_WRITE_ACCESS: 'schema_write_access',
|
|
25
|
+
INSTANCE_READ_ACCESS: 'instance_read_access',
|
|
26
|
+
INSTANCE_WRITE_ACCESS: 'instance_write_access',
|
|
27
|
+
COMMIT_READ_ACCESS: 'commit_read_access',
|
|
28
|
+
COMMIT_WRITE_ACCESS: 'commit_write_access',
|
|
29
|
+
META_READ_ACCESS: 'meta_read_access',
|
|
30
|
+
META_WRITE_ACCESS: 'meta_write_access',
|
|
31
|
+
CLASS_FRAME: 'class_frame',
|
|
32
|
+
BRANCH: 'branch',
|
|
33
|
+
CLONE: 'clone',
|
|
34
|
+
FETCH: 'fetch',
|
|
35
|
+
PUSH: 'push',
|
|
36
|
+
REBASE: 'rebase',
|
|
37
|
+
/* MANAGE_CAPABILITIES: 'manage_capabilities', */
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// encodeURI() will not encode: ~!@#$&*()=:/,;?+
|
|
41
|
+
// =%25team =%team
|
|
42
|
+
// terminusDB do not encode =@ too
|
|
43
|
+
Utils.encodeURISegment = function (str) {
|
|
44
|
+
if (typeof str !== 'string') return str;
|
|
45
|
+
str = encodeURI(str);
|
|
46
|
+
str = str.replace(/\?/g, '%3F');
|
|
47
|
+
// we not need = because the server does not encode it
|
|
48
|
+
// str = str.replace(/=/g, '%3D');
|
|
49
|
+
// str = str.replace(/@/g, '%40');
|
|
50
|
+
str = str.replace(/&/g, '%26');
|
|
51
|
+
str = str.replace(/\+/g, '%2B');
|
|
52
|
+
str = str.replace(/#/g, '%23');
|
|
53
|
+
return str;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
Utils.decodeURISegment = function (str) {
|
|
57
|
+
if (typeof str !== 'string') return str;
|
|
58
|
+
str = str.replace(/%3F/g, '?');
|
|
59
|
+
// str = str.replace(/%3D/g, '=');
|
|
60
|
+
// str = str.replace(/%26/g, '&');
|
|
61
|
+
str = str.replace(/%2B/g, '+');
|
|
62
|
+
str = str.replace(/%23/g, '#');
|
|
63
|
+
// str = str.replace(/%40/g, '@');
|
|
64
|
+
str = decodeURI(str);
|
|
65
|
+
return str;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
Utils.removeDocType = function (str) {
|
|
69
|
+
if (typeof str === 'string' && str.lastIndexOf('/') > -1) {
|
|
70
|
+
return str.substr(str.lastIndexOf('/') + 1);
|
|
71
|
+
}
|
|
72
|
+
return str;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// %253D%25team
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* default set of prefixes that will be used for URL compression
|
|
79
|
+
* @type {object}
|
|
80
|
+
*/
|
|
81
|
+
Utils.standard_urls = {
|
|
82
|
+
rdf: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
|
|
83
|
+
rdfs: 'http://www.w3.org/2000/01/rdf-schema#',
|
|
84
|
+
xsd: 'http://www.w3.org/2001/XMLSchema#',
|
|
85
|
+
xdd: 'http://terminusdb.com/schema/xdd#',
|
|
86
|
+
owl: 'http://www.w3.org/2002/07/owl#',
|
|
87
|
+
system: 'http://terminusdb.com/schema/system#',
|
|
88
|
+
vio: 'http://terminusdb.com/schema/vio#',
|
|
89
|
+
repo: 'http://terminusdb.com/schema/repository#',
|
|
90
|
+
layer: 'http://terminusdb.com/schema/layer#',
|
|
91
|
+
woql: 'http://terminusdb.com/schema/woql#',
|
|
92
|
+
ref: 'http://terminusdb.com/schema/ref#',
|
|
93
|
+
api: 'http://terminusdb.com/schema/api#',
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Encode document payload for GET
|
|
98
|
+
* @param {string | object} payload
|
|
99
|
+
* @returns {string}
|
|
100
|
+
*/
|
|
101
|
+
Utils.URIEncodePayload = function (payload) {
|
|
102
|
+
if (typeof payload === 'string') return encodeURIComponent(payload);
|
|
103
|
+
const payloadArr = [];
|
|
104
|
+
for (const key of Object.keys(payload)) {
|
|
105
|
+
if (typeof payload[key] === 'object') {
|
|
106
|
+
for (const keyElement of Object.keys(payload[key])) {
|
|
107
|
+
const valueElement = payload[key][keyElement];
|
|
108
|
+
payloadArr.push(
|
|
109
|
+
`${encodeURIComponent(keyElement)}=${encodeURIComponent(valueElement)}`,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
payloadArr.push(`${encodeURIComponent(key)}=${encodeURIComponent(payload[key])}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return payloadArr.join('&');
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Adds an entry to the list of known standard URL prefixes
|
|
121
|
+
* @param {string} prefix
|
|
122
|
+
* @param {string} url
|
|
123
|
+
*/
|
|
124
|
+
Utils.addURLPrefix = function (prefix, url) {
|
|
125
|
+
this.standard_urls[prefix] = url;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* is the object empty?
|
|
130
|
+
* returns true if the json object is empty
|
|
131
|
+
* @param {object|array} [obj]
|
|
132
|
+
* @returns {boolean}
|
|
133
|
+
*/
|
|
134
|
+
Utils.empty = function (obj) {
|
|
135
|
+
// null and undefined are "empty"
|
|
136
|
+
if (!obj) return true;
|
|
137
|
+
// Assume if it has a length property with a non-zero value
|
|
138
|
+
// that that property is correct.
|
|
139
|
+
if (obj.length > 0) return false;
|
|
140
|
+
if (obj.length === 0) return true;
|
|
141
|
+
// Otherwise, does it have any properties of its own?
|
|
142
|
+
// Note that this doesn't handle
|
|
143
|
+
// toString and valueOf enumeration bugs in IE < 9
|
|
144
|
+
// for (const key in obj) {
|
|
145
|
+
if (typeof obj === 'object') {
|
|
146
|
+
for (const key of Object.keys(obj)) {
|
|
147
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) return false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return true;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Generates a unique node id
|
|
155
|
+
* @param {string} [base]
|
|
156
|
+
* @returns {string}
|
|
157
|
+
*/
|
|
158
|
+
Utils.genBNID = function (base) {
|
|
159
|
+
base = base || '';
|
|
160
|
+
const r = Math.random()
|
|
161
|
+
.toString(36)
|
|
162
|
+
.substring(7);
|
|
163
|
+
const d = new Date();
|
|
164
|
+
const bnid = `${base}${r}${d.getTime()}`;// `doc:${base}${r}${d.getTime()}`
|
|
165
|
+
return bnid;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Returns the shorthand version (compressed to prefix:id ) of a url or
|
|
170
|
+
* false if there is none known for that URL
|
|
171
|
+
* @param {object | string} link
|
|
172
|
+
* @returns {string | boolean}
|
|
173
|
+
*/
|
|
174
|
+
|
|
175
|
+
Utils.getShorthand = function (link) {
|
|
176
|
+
// eslint-disable-next-line prefer-destructuring
|
|
177
|
+
if (typeof link === 'object' && link.length) link = link[0];
|
|
178
|
+
if (link && typeof link === 'string') {
|
|
179
|
+
for (const pref of Object.keys(this.standard_urls)) {
|
|
180
|
+
const full = this.standard_urls[pref];
|
|
181
|
+
if (link.substring(0, full.length) === full) {
|
|
182
|
+
const sh = `${pref}:${link.substring(full.length)}`;
|
|
183
|
+
return sh;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return false;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Compares 2 IRIs for equality by checking compressed and expanded versions of both sides
|
|
192
|
+
* @param {string} ida
|
|
193
|
+
* @param {string} idb
|
|
194
|
+
* @returns {boolean}
|
|
195
|
+
*/
|
|
196
|
+
Utils.compareIDs = function (ida, idb) {
|
|
197
|
+
if (ida === idb) return true;
|
|
198
|
+
if (this.unshorten(ida) === idb) return true;
|
|
199
|
+
if (this.shorten(ida) === idb) return true;
|
|
200
|
+
if (this.unshorten(ida) === this.unshorten(idb)) return true;
|
|
201
|
+
return false;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Shortens a URL to its compressed format - returns the full URL if not possible
|
|
206
|
+
* @param {string} [url]
|
|
207
|
+
* @param {string} [prefixes]
|
|
208
|
+
* @returns {string | undefined}
|
|
209
|
+
*/
|
|
210
|
+
// we don't have any more visualize prefix
|
|
211
|
+
// terminusdb://layer/data/Layer_44ce76721ebe179fdf2c015b0d38eadfa49de3ba
|
|
212
|
+
// eslint-disable-next-line no-unused-vars
|
|
213
|
+
Utils.shorten = function (url, prefixes) {
|
|
214
|
+
if (!url) return undefined;
|
|
215
|
+
if (url.indexOf('#') !== -1) {
|
|
216
|
+
const urlArr = url.split('#');
|
|
217
|
+
return urlArr.pop();
|
|
218
|
+
}
|
|
219
|
+
if (url.indexOf('terminusdb://') !== -1) {
|
|
220
|
+
const urlArr = url.split('/');
|
|
221
|
+
return urlArr.pop();
|
|
222
|
+
}
|
|
223
|
+
return url;
|
|
224
|
+
|
|
225
|
+
/* if (!url) return undefined
|
|
226
|
+
if (typeof url === 'function') return undefined
|
|
227
|
+
prefixes = prefixes || Utils.standard_urls
|
|
228
|
+
for (const pref in prefixes) {
|
|
229
|
+
if (prefixes[pref] === url.substring(0, prefixes[pref].length)) {
|
|
230
|
+
return `${pref}:${url.substring(prefixes[pref].length)}`
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return url */
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Expands a URL to its full URL format - returns the passed string if not possible to expand
|
|
238
|
+
* @param {string} [url]
|
|
239
|
+
* @returns {string | undefined}
|
|
240
|
+
*/
|
|
241
|
+
Utils.unshorten = function (url) {
|
|
242
|
+
if (!url) return undefined;
|
|
243
|
+
if (this.validURL(url)) return url;
|
|
244
|
+
if (!url) return url;
|
|
245
|
+
const bits = url.split(':');
|
|
246
|
+
if (bits[1]) {
|
|
247
|
+
if (this.standard_urls[bits[0]]) {
|
|
248
|
+
return this.standard_urls[bits[0]] + bits[1];
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return url;
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* shortens a jsonld document to its prefixed form
|
|
256
|
+
* @param {array|object|string} jsonld
|
|
257
|
+
* @param {string} [prefixes]
|
|
258
|
+
* @returns {string|array|object}
|
|
259
|
+
*/
|
|
260
|
+
|
|
261
|
+
Utils.json_shorten = function (jsonld, prefixes) {
|
|
262
|
+
const shorten_json_val = (val, prefixes) => {
|
|
263
|
+
if (Array.isArray(val)) {
|
|
264
|
+
const nvals = [];
|
|
265
|
+
for (let i = 0; i < val.length; i++) {
|
|
266
|
+
nvals.push(shorten_json_val(val[i], prefixes));
|
|
267
|
+
}
|
|
268
|
+
return nvals;
|
|
269
|
+
} if (typeof val === 'object') {
|
|
270
|
+
return this.json_shorten(val, prefixes);
|
|
271
|
+
} if (typeof val === 'string') {
|
|
272
|
+
return this.shorten(val, prefixes);
|
|
273
|
+
}
|
|
274
|
+
return val;
|
|
275
|
+
};
|
|
276
|
+
prefixes = prefixes || jsonld['@context'];
|
|
277
|
+
const nujson = {};
|
|
278
|
+
for (const key in jsonld) {
|
|
279
|
+
const nkey = key[0] === '@' ? key : this.shorten(key, prefixes);
|
|
280
|
+
const nval = shorten_json_val(jsonld[key], prefixes);
|
|
281
|
+
nujson[nkey] = nval;
|
|
282
|
+
}
|
|
283
|
+
return nujson;
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Unshortens a jsonld document to its full form
|
|
288
|
+
* @param {array|object|string} jsonld
|
|
289
|
+
* @param {string} [prefixes]
|
|
290
|
+
* @returns {string|array|object}
|
|
291
|
+
*/
|
|
292
|
+
|
|
293
|
+
Utils.json_unshorten = function (jsonld, prefixes) {
|
|
294
|
+
const unshorten_json_val = (val, prefixes) => {
|
|
295
|
+
if (Array.isArray(val)) {
|
|
296
|
+
const nvals = [];
|
|
297
|
+
for (let i = 0; i < val.length; i++) {
|
|
298
|
+
nvals.push(unshorten_json_val(val[i], prefixes));
|
|
299
|
+
}
|
|
300
|
+
return nvals;
|
|
301
|
+
} if (typeof val === 'object') {
|
|
302
|
+
return this.json_unshorten(val, prefixes);
|
|
303
|
+
} if (typeof val === 'string') {
|
|
304
|
+
return this.unshorten(val, prefixes);
|
|
305
|
+
}
|
|
306
|
+
return val;
|
|
307
|
+
};
|
|
308
|
+
prefixes = prefixes || jsonld['@context'];
|
|
309
|
+
const nujson = {};
|
|
310
|
+
for (const key in jsonld) {
|
|
311
|
+
const nkey = key[0] === '@' ? key : this.unshorten(key, prefixes);
|
|
312
|
+
const nval = unshorten_json_val(jsonld[key], prefixes);
|
|
313
|
+
nujson[nkey] = nval;
|
|
314
|
+
}
|
|
315
|
+
return nujson;
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Tests a string to see if it is a valid URL -
|
|
320
|
+
* Valid URLs are those that start with http:// or https://
|
|
321
|
+
*/
|
|
322
|
+
Utils.validURL = function (str) {
|
|
323
|
+
if (str && typeof str !== 'string') str = `${str}`;
|
|
324
|
+
if (str && (str.substring(0, 7) === 'http://' || str.substring(0, 8) === 'https://')) return true;
|
|
325
|
+
return false;
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Tests a string to see if it is a valid URL -
|
|
330
|
+
* Valid URLs are those that start with http:// or https://
|
|
331
|
+
* @param {string} str
|
|
332
|
+
* @param {string | object} [context]
|
|
333
|
+
* @param {boolean} [allow_shorthand]
|
|
334
|
+
* @returns {boolean}
|
|
335
|
+
*/
|
|
336
|
+
Utils.isIRI = function (str, context, allow_shorthand) {
|
|
337
|
+
if (!str) return false;
|
|
338
|
+
if (allow_shorthand && context && context[str.split(':')[0]]) return true;
|
|
339
|
+
if (context) {
|
|
340
|
+
for (pref in context) {
|
|
341
|
+
if (str.substring(0, context[pref].length) === context[pref]) return true;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
const prot = str.split(':')[0];
|
|
345
|
+
const valids = ['http', 'https', 'terminusdb'];
|
|
346
|
+
if (valids.indexOf(prot) !== -1) return true;
|
|
347
|
+
return false;
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Generates a text label from a URL
|
|
352
|
+
* @param {string} url
|
|
353
|
+
* @returns {string}
|
|
354
|
+
*/
|
|
355
|
+
Utils.labelFromURL = function (url) {
|
|
356
|
+
let nurl = this.urlFragment(url);
|
|
357
|
+
nurl = nurl || url;
|
|
358
|
+
if (nurl.lastIndexOf('/') < nurl.length - 1) {
|
|
359
|
+
nurl = nurl.substring(nurl.lastIndexOf('/') + 1);
|
|
360
|
+
}
|
|
361
|
+
nurl = nurl.replace(/_/g, ' ');
|
|
362
|
+
return nurl.charAt(0).toUpperCase() + nurl.slice(1);
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Generates a text label from a URL
|
|
367
|
+
*/
|
|
368
|
+
Utils.labelFromVariable = function (v) {
|
|
369
|
+
v = v.replace(/_/g, ' ');
|
|
370
|
+
return v.charAt(0).toUpperCase() + v.slice(1);
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* returns the fragment part of a URL (whether compressed or not)
|
|
375
|
+
*/
|
|
376
|
+
Utils.urlFragment = function (url) {
|
|
377
|
+
url = typeof url !== 'string' ? window.location.href : url;
|
|
378
|
+
let bits = url.split('#');
|
|
379
|
+
if (bits.length <= 1) {
|
|
380
|
+
if (!this.validURL(url)) {
|
|
381
|
+
bits = url.split(':');
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
if (bits.length >= 1) {
|
|
385
|
+
const [, urlStr] = bits;
|
|
386
|
+
|
|
387
|
+
if (urlStr) {
|
|
388
|
+
const [baseUrl] = urlStr.split('?');
|
|
389
|
+
url = baseUrl;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return url;
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* returns the last part of a URL after the last /
|
|
397
|
+
*/
|
|
398
|
+
Utils.lastURLBit = function (url) {
|
|
399
|
+
url = typeof url === 'undefined' ? window.location.href : url;
|
|
400
|
+
const [urlFirst] = url.split('#');
|
|
401
|
+
const [urlTmp] = urlFirst.split('?');
|
|
402
|
+
url = urlTmp.substring(url.lastIndexOf('/') + 1);
|
|
403
|
+
return url;
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* returns the a standard URL associated with a given prefix and extension
|
|
408
|
+
*/
|
|
409
|
+
Utils.getStdURL = function (pref, ext, url) {
|
|
410
|
+
if (this.standard_urls[pref]) {
|
|
411
|
+
if (url) {
|
|
412
|
+
if (url === this.standard_urls[pref] + ext) return url;
|
|
413
|
+
} else {
|
|
414
|
+
return this.standard_urls[pref] + ext;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return false;
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
/*
|
|
421
|
+
* Utility function adds v: to variables...
|
|
422
|
+
*/
|
|
423
|
+
Utils.addNamespacesToVariables = function (vars) {
|
|
424
|
+
const nvars = [];
|
|
425
|
+
for (let i = 0; i < vars.length; i++) {
|
|
426
|
+
if (vars[i]) nvars.push(this.addNamespaceToVariable(vars[i]));
|
|
427
|
+
}
|
|
428
|
+
return nvars;
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
Utils.addNamespaceToVariable = function (v) {
|
|
432
|
+
if (typeof v === 'string' && v.substring(0, 2) !== 'v:') return `v:${v}`;
|
|
433
|
+
return v;
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
/*
|
|
437
|
+
* Utility function removes v: prefix from a variable...
|
|
438
|
+
*/
|
|
439
|
+
Utils.removeNamespaceFromVariable = function (mvar) {
|
|
440
|
+
if (mvar.substring(0, 2) === 'v:') return mvar.substring(2);
|
|
441
|
+
return mvar;
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
/*
|
|
445
|
+
* Utility function removes v: prefix from an array of variables
|
|
446
|
+
*/
|
|
447
|
+
Utils.removeNamespacesFromVariables = function (vars) {
|
|
448
|
+
const nvars = [];
|
|
449
|
+
for (let i = 0; i < vars.length; i++) {
|
|
450
|
+
nvars.push(this.removeNamespaceFromVariable(vars[i]));
|
|
451
|
+
}
|
|
452
|
+
return nvars;
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
/*
|
|
456
|
+
* Utility function to extract a value from a config rule - if the value is a variable,
|
|
457
|
+
take the value of that variable instead
|
|
458
|
+
*/
|
|
459
|
+
Utils.getConfigValue = function (val, row) {
|
|
460
|
+
if (typeof val === 'string') val = this.removeNamespaceFromVariable(val);
|
|
461
|
+
if (typeof val === 'string' && row[val]) {
|
|
462
|
+
const rad = row[val];
|
|
463
|
+
if (rad && rad['@value']) return rad['@value'];
|
|
464
|
+
return rad;
|
|
465
|
+
}
|
|
466
|
+
return val;
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* TypeHelper bundles together utility functions dealing with datatypes
|
|
471
|
+
*/
|
|
472
|
+
Utils.TypeHelper = {};
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Returns true if the passed type is an xsd:string (compressed or not)
|
|
476
|
+
*/
|
|
477
|
+
Utils.TypeHelper.isStringType = function (stype) {
|
|
478
|
+
if (stype === 'http://www.w3.org/2001/XMLSchema#string') return true;
|
|
479
|
+
if (stype === 'xsd:string') return true;
|
|
480
|
+
return false;
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
Utils.TypeHelper.isDatatype = function (stype) {
|
|
484
|
+
const sh = Utils.shorten(stype);
|
|
485
|
+
if ((sh && sh.substring(0, 4) === 'xsd:') || sh.substring(0, 4) === 'xdd:') return true;
|
|
486
|
+
return false;
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Adds 3 order magnitude separators ( default ,) into big numbers for legibility
|
|
491
|
+
*/
|
|
492
|
+
Utils.TypeHelper.numberWithCommas = function (value, separator) {
|
|
493
|
+
separator = separator || ',';
|
|
494
|
+
if (value >= 1000 || value <= -1000) {
|
|
495
|
+
const parts = value.toString().split('.');
|
|
496
|
+
if (value <= -1000) parts[0] = parts[0].substring(1);
|
|
497
|
+
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, separator);
|
|
498
|
+
if (value <= -1000) value = `-${parts.join('.')}`;
|
|
499
|
+
else value = parts.join('.');
|
|
500
|
+
}
|
|
501
|
+
return value;
|
|
502
|
+
};
|
|
503
|
+
|
|
504
|
+
Utils.TypeHelper.formatBytes = function (bytes, decimals = 2) {
|
|
505
|
+
if (bytes === 0) return '0 Bytes';
|
|
506
|
+
const k = 1024;
|
|
507
|
+
const dm = decimals < 0 ? 0 : decimals;
|
|
508
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
|
509
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
510
|
+
return `${parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`;
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* List of supported datatypes
|
|
515
|
+
*/
|
|
516
|
+
Utils.TypeHelper.datatypes = [
|
|
517
|
+
'xdd:coordinate',
|
|
518
|
+
'xdd:coordinatePolyline',
|
|
519
|
+
'xdd:coordinatePolygon',
|
|
520
|
+
'xdd:dateRange',
|
|
521
|
+
'xdd:gYearRange',
|
|
522
|
+
'xdd:integerRange',
|
|
523
|
+
'xdd:decimalRange',
|
|
524
|
+
'xdd:cc',
|
|
525
|
+
'xdd:email',
|
|
526
|
+
'xdd:html',
|
|
527
|
+
'xdd:url',
|
|
528
|
+
'xsd:anySimpleType',
|
|
529
|
+
'xsd:string',
|
|
530
|
+
'xsd:boolean',
|
|
531
|
+
'xsd:decimal',
|
|
532
|
+
'xsd:double',
|
|
533
|
+
'xsd:float',
|
|
534
|
+
'xsd:time',
|
|
535
|
+
'xsd:date',
|
|
536
|
+
'xsd:dateTime',
|
|
537
|
+
'xsd:dateTimeStamp',
|
|
538
|
+
'xsd:gYear',
|
|
539
|
+
'xsd:gMonth',
|
|
540
|
+
'xsd:gDay',
|
|
541
|
+
'xsd:gYearMonth',
|
|
542
|
+
'xsd:gMonthDay',
|
|
543
|
+
'xsd:duration',
|
|
544
|
+
'xsd:yearMonthDuration',
|
|
545
|
+
'xsd:dayTimeDuration',
|
|
546
|
+
'xsd:byte',
|
|
547
|
+
'xsd:short',
|
|
548
|
+
'xsd:integer',
|
|
549
|
+
'xsd:long',
|
|
550
|
+
'xsd:unsignedByte',
|
|
551
|
+
'xsd:unsignedInt',
|
|
552
|
+
'xsd:unsignedLong',
|
|
553
|
+
'xsd:nonNegativeInteger',
|
|
554
|
+
'xsd:positiveInteger',
|
|
555
|
+
'xsd:negativeInteger',
|
|
556
|
+
'xsd:nonPositiveInteger',
|
|
557
|
+
'xsd:base64Binary',
|
|
558
|
+
'xsd:anyURI',
|
|
559
|
+
'xsd:language',
|
|
560
|
+
'xsd:normalizedString',
|
|
561
|
+
'xsd:token',
|
|
562
|
+
'xsd:NMTOKEN',
|
|
563
|
+
'xsd:Name',
|
|
564
|
+
'xsd:NCName',
|
|
565
|
+
'xsd:NOTATION',
|
|
566
|
+
'xsd:QName',
|
|
567
|
+
'xsd:ID',
|
|
568
|
+
'xsd:IDREF',
|
|
569
|
+
'xsd:ENTITY',
|
|
570
|
+
'rdf:XMLLiteral',
|
|
571
|
+
'rdf:PlainLiteral',
|
|
572
|
+
'rdfs:Literal',
|
|
573
|
+
'xdd:json',
|
|
574
|
+
];
|
|
575
|
+
|
|
576
|
+
Utils.TypeHelper.parseRangeValue = function (val, dividor) {
|
|
577
|
+
dividor = dividor || ',';
|
|
578
|
+
let vals = [];
|
|
579
|
+
if (typeof val === 'object' && val.length) {
|
|
580
|
+
vals = val;
|
|
581
|
+
} else if (val) {
|
|
582
|
+
if (typeof val !== 'string') {
|
|
583
|
+
val = `${val}`;
|
|
584
|
+
}
|
|
585
|
+
if (val.length && val.charAt(0) === '[' && val.charAt(val.length - 1) === ']') {
|
|
586
|
+
vals.push(val.substring(1, val.indexOf(dividor)));
|
|
587
|
+
vals.push(val.substring(val.indexOf(dividor) + 1, val.length - 1));
|
|
588
|
+
} else {
|
|
589
|
+
vals.push(val);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
return vals;
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* DateHelper bundles together utility functions dealing with xsd date types
|
|
597
|
+
*/
|
|
598
|
+
Utils.DateHelper = {};
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Takes an xsd time string and returns a structure {hour: HH, minute: MM,
|
|
602
|
+
* second ss.ssssss, timezone: tz}
|
|
603
|
+
*/
|
|
604
|
+
Utils.DateHelper.parseXsdTime = function (val) {
|
|
605
|
+
if (!val) return {};
|
|
606
|
+
const tz = this.extractXsdTimezone(val);
|
|
607
|
+
if (tz) {
|
|
608
|
+
val = val.substring(0, val.length - tz.length);
|
|
609
|
+
}
|
|
610
|
+
const parsed = {
|
|
611
|
+
hour: val.substring(0, 2),
|
|
612
|
+
minute: val.substring(3, 5),
|
|
613
|
+
second: val.substring(6),
|
|
614
|
+
timezone: tz,
|
|
615
|
+
};
|
|
616
|
+
return parsed;
|
|
617
|
+
};
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Takes an xsd time string and returns a structure {year: [-]YYYY, month: MM, day: dd}
|
|
621
|
+
*/
|
|
622
|
+
Utils.DateHelper.parseXsdDate = function (val) {
|
|
623
|
+
const tz = this.extractXsdTimezone(val);
|
|
624
|
+
if (tz) {
|
|
625
|
+
val = val.substring(0, val.length - tz.length);
|
|
626
|
+
}
|
|
627
|
+
let year;
|
|
628
|
+
if (val.substring(0, 1) === '-') {
|
|
629
|
+
year = val.substring(0, 5);
|
|
630
|
+
} else {
|
|
631
|
+
year = val.substring(0, 4);
|
|
632
|
+
}
|
|
633
|
+
let parsed;
|
|
634
|
+
if (year && Math.abs(year) < 10000) {
|
|
635
|
+
let month = val.substring(year.length + 1, year.length + 3);
|
|
636
|
+
if (month) {
|
|
637
|
+
month = parseInt(month, 10);
|
|
638
|
+
} else return false;
|
|
639
|
+
let day = val.substring(year.length + 4);
|
|
640
|
+
if (day) day = parseInt(day, 10);
|
|
641
|
+
else return false;
|
|
642
|
+
parsed = {
|
|
643
|
+
year,
|
|
644
|
+
month,
|
|
645
|
+
day,
|
|
646
|
+
timezone: tz,
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
return parsed;
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Parses a date string of type ty
|
|
654
|
+
*/
|
|
655
|
+
Utils.DateHelper.parseDate = function (ty, value) {
|
|
656
|
+
let parsed;
|
|
657
|
+
if (ty === 'xsd:date') {
|
|
658
|
+
parsed = this.parseXsdDate(value);
|
|
659
|
+
} else if (ty === 'xsd:time') {
|
|
660
|
+
parsed = this.parseXsdTime(value);
|
|
661
|
+
} else if (ty === 'xsd:dateTime') {
|
|
662
|
+
parsed = this.parseXsdDateTime(value);
|
|
663
|
+
} else if (ty === 'xsd:gYear') {
|
|
664
|
+
parsed = { year: value };
|
|
665
|
+
} else if (ty === 'xsd:gYearRange') {
|
|
666
|
+
parsed = { year: value };
|
|
667
|
+
} else if (ty === 'xsd:gMonth') {
|
|
668
|
+
parsed = { month: value.substring(2) };
|
|
669
|
+
} else if (ty === 'xsd:gDay') {
|
|
670
|
+
parsed = { day: value };
|
|
671
|
+
} else if (ty === 'xsd:gYearMonth') {
|
|
672
|
+
const bits = value.split('-');
|
|
673
|
+
while (bits.length < 2) bits.push('');
|
|
674
|
+
parsed = { year: bits[0], month: bits[1] };
|
|
675
|
+
} else if (ty === 'xsd:gMonthDay') {
|
|
676
|
+
const bits = value.split('-');
|
|
677
|
+
while (bits.length < 2) bits.push('');
|
|
678
|
+
parsed = { month: bits[0], day: bits[1] };
|
|
679
|
+
} else if (ty === 'xsd:dateTimeStamp') {
|
|
680
|
+
parsed = this.parseXsdDateTime(value);
|
|
681
|
+
}
|
|
682
|
+
return parsed;
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* adds appropriate padding to date type for xsd rules
|
|
687
|
+
*/
|
|
688
|
+
Utils.DateHelper.addXsdPadding = function (parsed) {
|
|
689
|
+
const nparsed = {};
|
|
690
|
+
if (typeof parsed.year !== 'undefined' && parsed.year !== false && parsed.year < 1000) {
|
|
691
|
+
if (Math.abs(parsed.year) < 10) nparsed.year = parsed.year < 0 ? `-000${Math.abs(parsed.year)}` : `000${parsed.year}`;
|
|
692
|
+
else if (Math.abs(parsed.year) < 100) nparsed.year = parsed.year < 0 ? `-00${Math.abs(parsed.year)}` : `00${parsed.year}`;
|
|
693
|
+
else nparsed.year = parsed.year < 0 ? `-0${Math.abs(parsed.year)}` : `0${parsed.year}`;
|
|
694
|
+
} else if (parsed.year) {
|
|
695
|
+
nparsed.year = parsed.year;
|
|
696
|
+
}
|
|
697
|
+
if (typeof parsed.month !== 'undefined' && parsed.month !== false && parsed.month < 10) {
|
|
698
|
+
nparsed.month = `0${parsed.month}`;
|
|
699
|
+
} else if (parsed.month) {
|
|
700
|
+
nparsed.month = parsed.month;
|
|
701
|
+
}
|
|
702
|
+
if (typeof parsed.day !== 'undefined' && parsed.day !== false && parsed.day < 10) {
|
|
703
|
+
nparsed.day = `0${parsed.day}`;
|
|
704
|
+
} else if (parsed.day) {
|
|
705
|
+
nparsed.day = parsed.day;
|
|
706
|
+
}
|
|
707
|
+
if (typeof parsed.hour !== 'undefined' && parsed.hour !== false && parsed.hour < 10) {
|
|
708
|
+
nparsed.hour = `0${parsed.hour}`;
|
|
709
|
+
} else if (parsed.hour) {
|
|
710
|
+
nparsed.hour = parsed.hour;
|
|
711
|
+
}
|
|
712
|
+
if (typeof parsed.minute !== 'undefined' && parsed.minute !== false && parsed.minute < 10) {
|
|
713
|
+
nparsed.minute = `0${parsed.minute}`;
|
|
714
|
+
} else if (parsed.minute) {
|
|
715
|
+
nparsed.minute = parsed.minute;
|
|
716
|
+
}
|
|
717
|
+
if (typeof parsed.second !== 'undefined' && parsed.second !== false && parsed.second < 10) {
|
|
718
|
+
nparsed.second = `0${parsed.second}`;
|
|
719
|
+
} else if (parsed.second) {
|
|
720
|
+
nparsed.second = parsed.second;
|
|
721
|
+
}
|
|
722
|
+
return nparsed;
|
|
723
|
+
};
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* generates an xsd string of type ty for the passed parsed structure (year, month, day, hour,
|
|
727
|
+
* minute, second, timezone)
|
|
728
|
+
*/
|
|
729
|
+
Utils.DateHelper.xsdFromParsed = function (parsed, ty) {
|
|
730
|
+
const xparsed = this.addXsdPadding(parsed);
|
|
731
|
+
let ret;
|
|
732
|
+
if (ty === 'xsd:gYear') {
|
|
733
|
+
ret = xparsed.year ? xparsed.year : false;
|
|
734
|
+
} else if (ty === 'xsd:time') {
|
|
735
|
+
return xparsed.hour && xparsed.minute && xparsed.second
|
|
736
|
+
? `${xparsed.hour}:${xparsed.minute}:${xparsed.second}`
|
|
737
|
+
: false;
|
|
738
|
+
} else if (ty === 'xsd:date') {
|
|
739
|
+
return xparsed.year && xparsed.month && xparsed.day
|
|
740
|
+
? `${xparsed.year}-${xparsed.month}-${xparsed.day}`
|
|
741
|
+
: false;
|
|
742
|
+
} else if (ty === 'xsd:dateTime' || ty === 'xsd:dateTimeStamp') {
|
|
743
|
+
ret = xparsed.year && xparsed.month && xparsed.day
|
|
744
|
+
? `${xparsed.year}-${xparsed.month}-${xparsed.day}T`
|
|
745
|
+
: false;
|
|
746
|
+
if (ret) {
|
|
747
|
+
ret += `${xparsed.hour ? xparsed.hour : '12'}:${
|
|
748
|
+
xparsed.minute ? xparsed.minute : '00'
|
|
749
|
+
}:${xparsed.second ? xparsed.second : '00'}`;
|
|
750
|
+
}
|
|
751
|
+
} else if (ty === 'xsd:gMonth') {
|
|
752
|
+
ret = xparsed.month ? `--${xparsed.month}` : false;
|
|
753
|
+
} else if (ty === 'xsd:gDay') {
|
|
754
|
+
ret = xparsed.day ? `---${xparsed.day}` : false;
|
|
755
|
+
} else if (ty === 'xsd:gYearMonth') {
|
|
756
|
+
ret = xparsed.year && xparsed.month ? `${xparsed.year}-${xparsed.month}` : false;
|
|
757
|
+
} else if (ty === 'xsd:gMonthDay') {
|
|
758
|
+
ret = xparsed.day && xparsed.month ? `--${xparsed.month}-${xparsed.day}` : false;
|
|
759
|
+
}
|
|
760
|
+
if (xparsed.timezone) {
|
|
761
|
+
ret += xparsed.timezone;
|
|
762
|
+
}
|
|
763
|
+
return ret;
|
|
764
|
+
};
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* Converts between a unix timestamp and a parsed structure
|
|
768
|
+
*/
|
|
769
|
+
Utils.DateHelper.convertTimestampToXsd = function (val) {
|
|
770
|
+
const a = new Date(val * 1000);
|
|
771
|
+
const parsed = {
|
|
772
|
+
year: a.getFullYear(),
|
|
773
|
+
month: a.getMonth() + 1,
|
|
774
|
+
day: a.getDate(),
|
|
775
|
+
hour: a.getHours(),
|
|
776
|
+
minute: a.getMinutes(),
|
|
777
|
+
second: a.getSeconds(),
|
|
778
|
+
};
|
|
779
|
+
return parsed;
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Parses an xsd date time into a structure
|
|
784
|
+
*/
|
|
785
|
+
Utils.DateHelper.parseXsdDateTime = function (val) {
|
|
786
|
+
if (!val) return {};
|
|
787
|
+
if (typeof val === 'number') {
|
|
788
|
+
return this.convertTimestampToXsd(val);
|
|
789
|
+
}
|
|
790
|
+
const tz = this.extractXsdTimezone(val);
|
|
791
|
+
if (tz) {
|
|
792
|
+
val = val.substring(0, val.length - tz.length);
|
|
793
|
+
}
|
|
794
|
+
const datetime = this.parseXsdDate(val);
|
|
795
|
+
const ptime = this.parseXsdTime(val.substring(val.indexOf('T') + 1));
|
|
796
|
+
|
|
797
|
+
for (const i of Object.keys(ptime)) {
|
|
798
|
+
datetime[i] = ptime[i];
|
|
799
|
+
}
|
|
800
|
+
datetime.timezone = tz;
|
|
801
|
+
return datetime;
|
|
802
|
+
};
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* Extracts the timezone data from an xsd date string
|
|
806
|
+
*/
|
|
807
|
+
Utils.DateHelper.extractXsdTimezone = function (val) {
|
|
808
|
+
if (typeof val === 'string' && val.endsWith('Z')) {
|
|
809
|
+
return 'Z';
|
|
810
|
+
}
|
|
811
|
+
if (typeof val === 'string' && (val.charAt(val.length - 6) === '+' || val.charAt(val.length - 6) === '-')) {
|
|
812
|
+
val.substring(val.length - 6);
|
|
813
|
+
}
|
|
814
|
+
return false;
|
|
815
|
+
};
|
|
816
|
+
|
|
817
|
+
module.exports = Utils;
|