jopi-toolkit 3.0.12 → 3.0.24
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/dist/jk_app/common.d.ts +2 -2
- package/dist/jk_app/common.js +7 -12
- package/dist/jk_app/common.js.map +1 -1
- package/dist/jk_data/index.d.ts +55 -0
- package/dist/jk_data/index.js +106 -0
- package/dist/jk_data/index.js.map +1 -0
- package/dist/jk_events/index.js +14 -6
- package/dist/jk_events/index.js.map +1 -1
- package/dist/jk_fs/jBundler_ifServer.d.ts +3 -3
- package/dist/jk_fs/jBundler_ifServer.js +26 -5
- package/dist/jk_fs/jBundler_ifServer.js.map +1 -1
- package/dist/jk_schemas/index.d.ts +156 -10
- package/dist/jk_schemas/index.js +130 -52
- package/dist/jk_schemas/index.js.map +1 -1
- package/dist/jk_term/index.d.ts +2 -0
- package/dist/jk_term/index.js +2 -0
- package/dist/jk_term/index.js.map +1 -1
- package/dist/jk_timer/index.d.ts +2 -0
- package/dist/jk_timer/index.js +2 -0
- package/dist/jk_timer/index.js.map +1 -1
- package/dist/jk_tools/jBundler_ifServer.d.ts +1 -0
- package/dist/jk_tools/jBundler_ifServer.js +40 -10
- package/dist/jk_tools/jBundler_ifServer.js.map +1 -1
- package/package.json +9 -8
- package/src/jk_app/common.js +442 -0
- package/src/jk_app/common.ts +7 -17
- package/src/jk_crypto/jBundler_ifServer.js +16 -0
- package/src/jk_data/index.js +155 -0
- package/src/jk_data/index.ts +166 -0
- package/src/jk_events/index.js +221 -0
- package/src/jk_events/index.ts +18 -7
- package/src/jk_fs/index.js +2 -0
- package/src/jk_fs/jBundler_ifServer.js +764 -0
- package/src/jk_fs/jBundler_ifServer.ts +26 -5
- package/src/jk_logs/index.js +371 -0
- package/src/jk_logs/jBundler_ifServer.js +24 -0
- package/src/jk_schemas/index.js +134 -52
- package/src/jk_schemas/index.ts +334 -78
- package/src/jk_term/index.js +2 -0
- package/src/jk_term/index.ts +3 -0
- package/src/jk_thread/common.js +7 -0
- package/src/jk_timer/index.js +2 -0
- package/src/jk_timer/index.ts +3 -0
- package/src/jk_tools/common.js +101 -0
- package/src/jk_tools/index.js +1 -0
- package/src/jk_tools/jBundler_ifServer.js +215 -0
- package/src/jk_tools/jBundler_ifServer.ts +49 -11
- package/src/jk_what/jBundler_ifServer.js +5 -0
- package/dist/jk_translate/index.d.ts +0 -21
- package/dist/jk_translate/index.js +0 -56
- package/dist/jk_translate/index.js.map +0 -1
- package/src/jk_os/jBundler_ifServer.js +0 -132
- package/src/jk_translate/index.ts +0 -85
package/src/jk_schemas/index.ts
CHANGED
|
@@ -41,67 +41,13 @@ export interface ValidationErrors {
|
|
|
41
41
|
fields?: Record<string, FieldError>;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
const byTypeValidator: Record<string, (v: any, fieldInfos: SchemaFieldInfos) => void> = {
|
|
45
|
-
"string": (v, f) => {
|
|
46
|
-
if (typeof v !== "string") {
|
|
47
|
-
declareError(f.errorMessage_theValueIsInvalid || `Value must be a string`, "INVALID_TYPE");
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
let sf = f as ScString<any>;
|
|
52
|
-
|
|
53
|
-
if ((sf.minLength!==undefined) && (v.length < sf.minLength)) {
|
|
54
|
-
declareError(sf.errorMessage_minLength || `Value must be at least ${sf.minLength} characters long`, "INVALID_LENGTH");
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if ((sf.maxLength!==undefined) && (v.length > sf.maxLength)) {
|
|
59
|
-
declareError(sf.errorMessage_maxLength || `Value must be less than ${sf.maxLength} characters long`, "INVALID_LENGTH");
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
|
|
64
|
-
"number": (v, f) => {
|
|
65
|
-
if (typeof v !== "number") {
|
|
66
|
-
declareError(f.errorMessage_theValueIsInvalid || `Value must be a number`, "INVALID_TYPE");
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
let sf = f as ScNumber<any>;
|
|
70
|
-
|
|
71
|
-
if ((sf.minValue!==undefined) && (v < sf.minValue)) {
|
|
72
|
-
declareError(sf.errorMessage_minValue || `Value must be at least ${sf.minValue}`, "INVALID_LENGTH");
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if ((sf.maxValue!==undefined) && (v > sf.maxValue)) {
|
|
77
|
-
declareError(sf.errorMessage_maxValue || `Value must be less than ${sf.maxValue}`, "INVALID_LENGTH");
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
|
|
82
|
-
"boolean": (v, f) => {
|
|
83
|
-
if (typeof v !== "boolean") {
|
|
84
|
-
declareError(f.errorMessage_theValueIsInvalid || `Value must be a boolean`, "INVALID_TYPE");
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
let sf = f as ScBoolean<any>;
|
|
88
|
-
|
|
89
|
-
if (sf.requireTrue) {
|
|
90
|
-
if (v!==true) {
|
|
91
|
-
declareError(sf.errorMessage_requireTrue || `Value must be true`, "INVALID_VALUE");
|
|
92
|
-
}
|
|
93
|
-
} else if (sf.requireFalse) {
|
|
94
|
-
if (v!==false) {
|
|
95
|
-
declareError(sf.errorMessage_requireFalse || `Value must be false`, "INVALID_VALUE");
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
44
|
export function validateSchema(data: any, schema: Schema): ValidationErrors|undefined {
|
|
45
|
+
// Normalize the data.
|
|
46
|
+
// It's a step where we apply automatic corrections.
|
|
47
|
+
//
|
|
102
48
|
if (schema.schemaMeta.normalize) {
|
|
103
49
|
try {
|
|
104
|
-
schema.schemaMeta.normalize(data);
|
|
50
|
+
schema.schemaMeta.normalize(data, gValueCheckingHelper);
|
|
105
51
|
}
|
|
106
52
|
catch (e: any) {
|
|
107
53
|
if (e instanceof SchemaError) {
|
|
@@ -116,6 +62,13 @@ export function validateSchema(data: any, schema: Schema): ValidationErrors|unde
|
|
|
116
62
|
}
|
|
117
63
|
}
|
|
118
64
|
|
|
65
|
+
// >>> Check each field individually.
|
|
66
|
+
|
|
67
|
+
// Each time it will:
|
|
68
|
+
// - Normalize the value.
|
|
69
|
+
// - Check if optional + undefined.
|
|
70
|
+
// - Apply validator for the field type.
|
|
71
|
+
|
|
119
72
|
let fieldErrors: Record<string, FieldError>|undefined;
|
|
120
73
|
|
|
121
74
|
for (let fieldName in schema.desc) {
|
|
@@ -127,7 +80,7 @@ export function validateSchema(data: any, schema: Schema): ValidationErrors|unde
|
|
|
127
80
|
|
|
128
81
|
if (field.normalize) {
|
|
129
82
|
defaultErrorMessage = field.errorMessage_theValueIsInvalid;
|
|
130
|
-
field.normalize(value, data);
|
|
83
|
+
field.normalize(value, data, gValueCheckingHelper);
|
|
131
84
|
}
|
|
132
85
|
|
|
133
86
|
if (!field.optional) {
|
|
@@ -150,7 +103,7 @@ export function validateSchema(data: any, schema: Schema): ValidationErrors|unde
|
|
|
150
103
|
|
|
151
104
|
if (field.validator) {
|
|
152
105
|
defaultErrorMessage = field.errorMessage_theValueIsInvalid;
|
|
153
|
-
field.validator(value, data);
|
|
106
|
+
field.validator(value, data, gValueCheckingHelper);
|
|
154
107
|
}
|
|
155
108
|
}
|
|
156
109
|
catch (e: any) {
|
|
@@ -168,9 +121,12 @@ export function validateSchema(data: any, schema: Schema): ValidationErrors|unde
|
|
|
168
121
|
}
|
|
169
122
|
}
|
|
170
123
|
|
|
124
|
+
// >>> Validate the whole fields.
|
|
125
|
+
// Allow validating if values are ok with each others.
|
|
126
|
+
|
|
171
127
|
if (schema.schemaMeta.validate) {
|
|
172
128
|
try {
|
|
173
|
-
schema.schemaMeta.validate(data);
|
|
129
|
+
schema.schemaMeta.validate(data, gValueCheckingHelper);
|
|
174
130
|
}
|
|
175
131
|
catch (e: any) {
|
|
176
132
|
if (e instanceof SchemaError) {
|
|
@@ -186,10 +142,27 @@ export function validateSchema(data: any, schema: Schema): ValidationErrors|unde
|
|
|
186
142
|
}
|
|
187
143
|
}
|
|
188
144
|
|
|
145
|
+
// No error ? --> undefined.
|
|
146
|
+
// Otherwise returns the errors.
|
|
147
|
+
//
|
|
189
148
|
if (!fieldErrors) return undefined;
|
|
190
149
|
return {fields: fieldErrors};
|
|
191
150
|
}
|
|
192
151
|
|
|
152
|
+
const byTypeValidator: Record<string, (v: any, fieldInfos: SchemaFieldInfos) => void> = {};
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* A helper allowing to make field validation easier.
|
|
156
|
+
* Is sent to normalize and validate functions.
|
|
157
|
+
*/
|
|
158
|
+
class ValueCheckingHelper {
|
|
159
|
+
declareError(message?: string, errorCode?: string) {
|
|
160
|
+
throw new SchemaError(message, errorCode);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const gValueCheckingHelper = new ValueCheckingHelper();
|
|
165
|
+
|
|
193
166
|
//endregion
|
|
194
167
|
|
|
195
168
|
//region Registry
|
|
@@ -236,11 +209,50 @@ const gRegistry: Record<string, RegistryEntry> = {};
|
|
|
236
209
|
//region Schema
|
|
237
210
|
|
|
238
211
|
export function schema<T extends SchemaDescriptor>(descriptor: T, meta?: SchemaMeta): Schema & { desc: T } {
|
|
239
|
-
return
|
|
212
|
+
return new SchemaImpl(descriptor, meta || {});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
class SchemaImpl<T extends SchemaDescriptor> implements Schema {
|
|
216
|
+
constructor(public readonly desc: T, public readonly schemaMeta: SchemaMeta) {
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
toJson(): SchemaInfo {
|
|
220
|
+
return toJson(this);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
addDataNormalizer(f: (allValues: any, checkHelper: ValueCheckingHelper) => void): this {
|
|
224
|
+
if (!this.schemaMeta.normalize) {
|
|
225
|
+
this.schemaMeta.normalize = f;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const f1 = this.schemaMeta.normalize;
|
|
229
|
+
|
|
230
|
+
this.schemaMeta.normalize = function (values, helper) {
|
|
231
|
+
f1(values, helper);
|
|
232
|
+
f(values, helper);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return this;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
addDataValidator(f: (allValues: any, checkHelper: ValueCheckingHelper) => void): this {
|
|
239
|
+
if (!this.schemaMeta.validate) {
|
|
240
|
+
this.schemaMeta.validate = f;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const f1 = this.schemaMeta.validate;
|
|
244
|
+
|
|
245
|
+
this.schemaMeta.validate = function (values, helper) {
|
|
246
|
+
f1(values, helper);
|
|
247
|
+
f(values, helper);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return this;
|
|
251
|
+
}
|
|
240
252
|
}
|
|
241
253
|
|
|
242
254
|
export interface SchemaDescriptor {
|
|
243
|
-
[field: string]:
|
|
255
|
+
[field: string]: Field;
|
|
244
256
|
}
|
|
245
257
|
|
|
246
258
|
export interface SchemaMeta {
|
|
@@ -248,8 +260,8 @@ export interface SchemaMeta {
|
|
|
248
260
|
description?: string;
|
|
249
261
|
[key: string]: any;
|
|
250
262
|
|
|
251
|
-
normalize?: (allValues: any) => void;
|
|
252
|
-
validate?: (allValues: any) => void;
|
|
263
|
+
normalize?: (allValues: any, checkHelper: ValueCheckingHelper) => void;
|
|
264
|
+
validate?: (allValues: any, checkHelper: ValueCheckingHelper) => void;
|
|
253
265
|
}
|
|
254
266
|
|
|
255
267
|
export interface SchemaInfo {
|
|
@@ -258,6 +270,26 @@ export interface SchemaInfo {
|
|
|
258
270
|
}
|
|
259
271
|
|
|
260
272
|
export interface Schema extends SchemaInfo {
|
|
273
|
+
/**
|
|
274
|
+
* Get serializable data describing this schema.
|
|
275
|
+
*/
|
|
276
|
+
toJson(): SchemaInfo;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Add a function whose role is to normalize the data.
|
|
280
|
+
*
|
|
281
|
+
* Cumulating: if a normalize function has already been added,
|
|
282
|
+
* then the previous function will be called before this one.
|
|
283
|
+
*/
|
|
284
|
+
addDataNormalizer(f: (allValues: any, checkHelper: ValueCheckingHelper) => void): this;
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Add a function whose role is to validate the data.
|
|
288
|
+
*
|
|
289
|
+
* Cumulating: if a validate function has already been added,
|
|
290
|
+
* then the previous function will be called before this one.
|
|
291
|
+
*/
|
|
292
|
+
addDataValidator(f: (allValues: any, checkHelper: ValueCheckingHelper) => void): this;
|
|
261
293
|
}
|
|
262
294
|
|
|
263
295
|
export function toJson(schema: Schema): SchemaInfo {
|
|
@@ -275,17 +307,113 @@ export function toJson(schema: Schema): SchemaInfo {
|
|
|
275
307
|
* ```
|
|
276
308
|
*/
|
|
277
309
|
export type SchemaToType<S extends Schema> =
|
|
278
|
-
// 1. On accède au descripteur de schéma S['desc']
|
|
279
|
-
// 2. On itère sur ses clés K
|
|
280
|
-
// 3. On filtre les champs obligatoires (Opt = false)
|
|
281
310
|
{ [K in keyof S['desc'] as S['desc'][K] extends ScField<any, false> ? K : never]:
|
|
282
|
-
// 4. On infère le type T du champ
|
|
283
311
|
S['desc'][K] extends ScField<infer T, any> ? T : never }
|
|
284
312
|
|
|
285
|
-
// 5. On fusionne avec les champs optionnels (Opt = true)
|
|
286
313
|
& { [K in keyof S['desc'] as S['desc'][K] extends ScField<any, true> ? K : never] ?:
|
|
287
314
|
S['desc'][K] extends ScField<infer T, any> ? T : never };
|
|
288
315
|
|
|
316
|
+
export interface ScOnTableRenderingInfo {
|
|
317
|
+
/**
|
|
318
|
+
* The title to use if rendering with a Table.
|
|
319
|
+
*/
|
|
320
|
+
title?: string;
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* If true, then allows hiding the column
|
|
324
|
+
* when rendering into a UI table component.
|
|
325
|
+
*/
|
|
326
|
+
enableHiding?: boolean;
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* If true, then the table column is hidden by default.
|
|
330
|
+
*/
|
|
331
|
+
defaultHidden?: boolean;
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* If true, then the table column is hidden and remain hidden.
|
|
335
|
+
*/
|
|
336
|
+
alwaysHidden?: boolean;
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* If true, then allows sorting the column
|
|
340
|
+
* when rendering into a UI table component.
|
|
341
|
+
*/
|
|
342
|
+
enableSorting?: boolean;
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* If true, then allows editing the column
|
|
346
|
+
* when rendering into a UI table component.
|
|
347
|
+
*/
|
|
348
|
+
enableEditing?: boolean;
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Contains the name of the renderer to user for the header.
|
|
352
|
+
*/
|
|
353
|
+
rendererForHeader?: string;
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Contains the name of the renderer to user for the cell.
|
|
357
|
+
*/
|
|
358
|
+
rendererForCell?: string;
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Allows setting the column grow rule.
|
|
362
|
+
*/
|
|
363
|
+
columnGrow?: "takeAllPlace" | "takeMinPlace";
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Allows defining extra-css class for rendering the cells.
|
|
367
|
+
*/
|
|
368
|
+
cellCssClass?: string;
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Allows defining extra-css class for rendering the header.
|
|
372
|
+
*/
|
|
373
|
+
headerCssClass?: string;
|
|
374
|
+
|
|
375
|
+
textAlign?: "left" | "center" | "right";
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Get information about how storing this field.
|
|
380
|
+
*/
|
|
381
|
+
export interface ScFieldStore {
|
|
382
|
+
/**
|
|
383
|
+
* Allow knowing if a BDD index must be created for this field.
|
|
384
|
+
* The default is true.
|
|
385
|
+
*/
|
|
386
|
+
mustIndex?: boolean;
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Allow knowing if this field is the primary key.
|
|
390
|
+
* If more than one primary is set, then a composed key will be created.
|
|
391
|
+
* The default is false.
|
|
392
|
+
*/
|
|
393
|
+
isPrimaryKey?: boolean;
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* The column name to use when storing this field in a database.
|
|
397
|
+
* The default is the field name.
|
|
398
|
+
*/
|
|
399
|
+
colName?: string;
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* An indication on the size of the data to store.
|
|
403
|
+
* The default is "default".
|
|
404
|
+
*
|
|
405
|
+
* - big: for storing large strings / binary.
|
|
406
|
+
* - medium: for storing item with a common size.
|
|
407
|
+
* - tiny: for storing small strings / binary.
|
|
408
|
+
*/
|
|
409
|
+
dataSize?: "tiny" | "medium" | "big";
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Allow forcing the type name for the BDD.
|
|
413
|
+
*/
|
|
414
|
+
databaseType?: string;
|
|
415
|
+
}
|
|
416
|
+
|
|
289
417
|
export interface ScField<T, Opt extends boolean> {
|
|
290
418
|
title: string;
|
|
291
419
|
type: string;
|
|
@@ -298,15 +426,37 @@ export interface ScField<T, Opt extends boolean> {
|
|
|
298
426
|
errorMessage_theDataTypeIsInvalid?: string;
|
|
299
427
|
errorMessage_theValueIsInvalid?: string;
|
|
300
428
|
|
|
301
|
-
|
|
302
|
-
|
|
429
|
+
/**
|
|
430
|
+
* A function used to normalize the field value.
|
|
431
|
+
*/
|
|
432
|
+
normalize?: (value: T, allValues: any, valueCheckingHelp: ValueCheckingHelper) => void;
|
|
303
433
|
|
|
434
|
+
/**
|
|
435
|
+
* A function used to validate the field.
|
|
436
|
+
*/
|
|
437
|
+
validator?: (value: T, allValues: any, valueCheckingHelp: ValueCheckingHelper) => void;
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Meta-data associated with this field.
|
|
441
|
+
* The usage is free, you can use it for whatever you want.
|
|
442
|
+
*/
|
|
304
443
|
metas?: Record<string, string>;
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Get information about how to render this field in a data table.
|
|
447
|
+
*/
|
|
448
|
+
onTableRendering?: ScOnTableRenderingInfo;
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Get information about how storing this field.
|
|
452
|
+
*/
|
|
453
|
+
store?: ScFieldStore;
|
|
305
454
|
}
|
|
306
455
|
|
|
307
|
-
export type
|
|
456
|
+
export type Field = ScField<any, any>;
|
|
457
|
+
export type SchemaFieldInfos = Field;
|
|
308
458
|
|
|
309
|
-
type OnlyInfos<T> = Omit<
|
|
459
|
+
type OnlyInfos<T> = Omit<T, "title" | "optional" | "type">;
|
|
310
460
|
|
|
311
461
|
//endregion
|
|
312
462
|
|
|
@@ -314,7 +464,7 @@ type OnlyInfos<T> = Omit<Omit<Omit<T, "title">, "optional">, "type">;
|
|
|
314
464
|
|
|
315
465
|
//region String
|
|
316
466
|
|
|
317
|
-
export interface ScString<Opt extends boolean> extends ScField<string, Opt> {
|
|
467
|
+
export interface ScString<Opt extends boolean = boolean> extends ScField<string, Opt> {
|
|
318
468
|
minLength?: number;
|
|
319
469
|
errorMessage_minLength?: string;
|
|
320
470
|
|
|
@@ -333,11 +483,30 @@ export function string<Opt extends boolean>(title: string, optional: Opt, infos?
|
|
|
333
483
|
return {...infos, title, optional, type: "string"};
|
|
334
484
|
}
|
|
335
485
|
|
|
486
|
+
byTypeValidator["string"] = (v,f) => {
|
|
487
|
+
if (typeof v !== "string") {
|
|
488
|
+
declareError(f.errorMessage_theValueIsInvalid || `Value must be a string`, "INVALID_TYPE");
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
let sf = f as ScString<any>;
|
|
493
|
+
|
|
494
|
+
if ((sf.minLength !== undefined) && (v.length < sf.minLength)) {
|
|
495
|
+
declareError(sf.errorMessage_minLength || `Value must be at least ${sf.minLength} characters long`, "INVALID_LENGTH");
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
if ((sf.maxLength !== undefined) && (v.length > sf.maxLength)) {
|
|
500
|
+
declareError(sf.errorMessage_maxLength || `Value must be less than ${sf.maxLength} characters long`, "INVALID_LENGTH");
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
|
|
336
505
|
//endregion
|
|
337
506
|
|
|
338
507
|
//region Boolean
|
|
339
508
|
|
|
340
|
-
export interface ScBoolean<Opt extends boolean> extends ScField<boolean, Opt> {
|
|
509
|
+
export interface ScBoolean<Opt extends boolean = boolean> extends ScField<boolean, Opt> {
|
|
341
510
|
requireTrue?: boolean;
|
|
342
511
|
errorMessage_requireTrue?: string;
|
|
343
512
|
|
|
@@ -349,30 +518,117 @@ export function boolean<Opt extends boolean>(title: string, optional: Opt, infos
|
|
|
349
518
|
return {...infos, title, optional, type: "boolean"};
|
|
350
519
|
}
|
|
351
520
|
|
|
521
|
+
byTypeValidator["boolean"] = (v, f) => {
|
|
522
|
+
if (typeof v !== "boolean") {
|
|
523
|
+
declareError(f.errorMessage_theValueIsInvalid || `Value must be a boolean`, "INVALID_TYPE");
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
let sf = f as ScBoolean<any>;
|
|
527
|
+
|
|
528
|
+
if (sf.requireTrue) {
|
|
529
|
+
if (v !== true) {
|
|
530
|
+
declareError(sf.errorMessage_requireTrue || `Value must be true`, "INVALID_VALUE");
|
|
531
|
+
}
|
|
532
|
+
} else if (sf.requireFalse) {
|
|
533
|
+
if (v !== false) {
|
|
534
|
+
declareError(sf.errorMessage_requireFalse || `Value must be false`, "INVALID_VALUE");
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
|
|
352
539
|
//endregion
|
|
353
540
|
|
|
354
541
|
//region Number
|
|
355
542
|
|
|
356
|
-
export interface ScNumber<Opt extends boolean> extends ScField<number, Opt> {
|
|
543
|
+
export interface ScNumber<Opt extends boolean = boolean> extends ScField<number, Opt> {
|
|
357
544
|
minValue?: number;
|
|
358
545
|
errorMessage_minValue?: string;
|
|
359
546
|
|
|
360
547
|
maxValue?: number;
|
|
361
548
|
errorMessage_maxValue?: string;
|
|
362
549
|
|
|
363
|
-
// TODO: allowDecimal
|
|
364
550
|
allowDecimal?: boolean;
|
|
551
|
+
|
|
365
552
|
roundMethod?: "round" | "floor" | "ceil";
|
|
366
553
|
errorMessage_dontAllowDecimal?: string;
|
|
367
554
|
|
|
368
555
|
incrStep?: number;
|
|
369
556
|
placeholder?: string;
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Allows displaying this value as a simple
|
|
560
|
+
* number, or a current, or a percent.
|
|
561
|
+
*/
|
|
562
|
+
displayType?: "decimal" | "currency" | "percent";
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* The regional currency format to use for formating.
|
|
566
|
+
* Ex: "en-US", "fr-FR".
|
|
567
|
+
*/
|
|
568
|
+
localFormat?: string;
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* The type of currency.
|
|
572
|
+
* Ex: "USD".
|
|
573
|
+
*/
|
|
574
|
+
currency?: string;
|
|
370
575
|
}
|
|
371
576
|
|
|
372
577
|
export function number<Opt extends boolean>(title: string, optional: Opt, infos?: OnlyInfos<ScNumber<Opt>>): ScNumber<Opt> {
|
|
373
578
|
return {...infos, title, optional, type: "number"};
|
|
374
579
|
}
|
|
375
580
|
|
|
581
|
+
export function formatNumber(value: string, fieldNumber: ScNumber, defaultLocalFormat: string = "en-US", defaultCurrency: string = "USD") {
|
|
582
|
+
const amount = parseFloat(value);
|
|
583
|
+
|
|
584
|
+
let localFormat = fieldNumber.localFormat || defaultLocalFormat;
|
|
585
|
+
|
|
586
|
+
switch (fieldNumber.displayType) {
|
|
587
|
+
case "currency":
|
|
588
|
+
return new Intl.NumberFormat(localFormat, {
|
|
589
|
+
style: "currency",
|
|
590
|
+
currency: fieldNumber.currency || defaultCurrency,
|
|
591
|
+
}).format(amount);
|
|
592
|
+
default:
|
|
593
|
+
return new Intl.NumberFormat(localFormat, {style: fieldNumber.displayType || "decimal"}).format(amount);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
byTypeValidator["number"] = (v,f) => {
|
|
598
|
+
if (typeof v !== "number") {
|
|
599
|
+
declareError(f.errorMessage_theValueIsInvalid || `Value must be a number`, "INVALID_TYPE");
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
let sf = f as ScNumber<any>;
|
|
603
|
+
|
|
604
|
+
if ((sf.minValue!==undefined) && (v < sf.minValue)) {
|
|
605
|
+
declareError(sf.errorMessage_minValue || `Value must be at least ${sf.minValue}`, "INVALID_LENGTH");
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if ((sf.maxValue!==undefined) && (v > sf.maxValue)) {
|
|
610
|
+
declareError(sf.errorMessage_maxValue || `Value must be less than ${sf.maxValue}`, "INVALID_LENGTH");
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
//endregion
|
|
616
|
+
|
|
617
|
+
//region Currency
|
|
618
|
+
|
|
619
|
+
export function currency<Opt extends boolean>(title: string, optional: Opt, infos?: OnlyInfos<ScNumber<Opt>>): ScNumber<Opt> {
|
|
620
|
+
return number(title, optional, {...infos, displayType: "currency"})
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
//endregion
|
|
624
|
+
|
|
625
|
+
//region Percent
|
|
626
|
+
|
|
627
|
+
export function percent<Opt extends boolean>(title: string, optional: Opt, infos?: OnlyInfos<ScNumber<Opt>>): ScNumber<Opt> {
|
|
628
|
+
return number(title, optional, {...infos, displayType: "percent"})
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
|
|
376
632
|
//endregion
|
|
377
633
|
|
|
378
634
|
//region File
|
package/src/jk_term/index.js
CHANGED
|
@@ -114,6 +114,8 @@ export var logBgRed = buildLogger(B_RED);
|
|
|
114
114
|
export var textBgRed = buildWriter(B_RED);
|
|
115
115
|
export var logBlue = buildLogger(C_BLUE);
|
|
116
116
|
export var textBlue = buildWriter(C_BLUE);
|
|
117
|
+
export var logGrey = buildLogger(C_GREY);
|
|
118
|
+
export var textGrey = buildWriter(C_GREY);
|
|
117
119
|
export var logBgBlue = buildLogger(B_BLUE, C_WHITE);
|
|
118
120
|
export var textBgBlue = buildWriter(B_BLUE, C_WHITE);
|
|
119
121
|
export var logGreen = buildLogger(C_GREEN);
|
package/src/jk_term/index.ts
CHANGED
|
@@ -105,6 +105,9 @@ export const textBgRed = buildWriter(B_RED);
|
|
|
105
105
|
export const logBlue = buildLogger(C_BLUE);
|
|
106
106
|
export const textBlue = buildWriter(C_BLUE);
|
|
107
107
|
|
|
108
|
+
export const logGrey = buildLogger(C_GREY);
|
|
109
|
+
export const textGrey = buildWriter(C_GREY);
|
|
110
|
+
|
|
108
111
|
export const logBgBlue = buildLogger(B_BLUE, C_WHITE);
|
|
109
112
|
export const textBgBlue = buildWriter(B_BLUE, C_WHITE);
|
|
110
113
|
|
package/src/jk_timer/index.js
CHANGED
|
@@ -95,6 +95,8 @@ export function deferred(callback) {
|
|
|
95
95
|
export function tick(timeInMs) {
|
|
96
96
|
return new Promise(function (resolve) { return setTimeout(resolve, timeInMs); });
|
|
97
97
|
}
|
|
98
|
+
export var sleep = tick;
|
|
99
|
+
export var pause = tick;
|
|
98
100
|
export function chrono(mustSaveMeasures) {
|
|
99
101
|
return new ChronoImpl(mustSaveMeasures);
|
|
100
102
|
}
|
package/src/jk_timer/index.ts
CHANGED
|
@@ -78,6 +78,9 @@ export function tick(timeInMs: number): Promise<void> {
|
|
|
78
78
|
return new Promise(resolve => setTimeout(resolve, timeInMs));
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
export const sleep = tick;
|
|
82
|
+
export const pause = tick;
|
|
83
|
+
|
|
81
84
|
export function chrono(mustSaveMeasures: boolean): Chrono {
|
|
82
85
|
return new ChronoImpl(mustSaveMeasures)
|
|
83
86
|
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
export function generateUUIDv4() {
|
|
13
|
+
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
|
|
14
|
+
return crypto.randomUUID();
|
|
15
|
+
}
|
|
16
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
17
|
+
var r = Math.random() * 16 | 0;
|
|
18
|
+
var v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
19
|
+
return v.toString(16);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export function isUUIDv4(text) {
|
|
23
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(text);
|
|
24
|
+
}
|
|
25
|
+
export function getErrorMessage(e) {
|
|
26
|
+
if (e instanceof Error)
|
|
27
|
+
return e.message;
|
|
28
|
+
return "" + e;
|
|
29
|
+
}
|
|
30
|
+
export function applyDefaults(source, defaults) {
|
|
31
|
+
if (!source)
|
|
32
|
+
source = {};
|
|
33
|
+
return __assign(__assign({}, defaults), source);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Allow knowing the file path of the function calling us.
|
|
37
|
+
*/
|
|
38
|
+
export function getCallerFilePath() {
|
|
39
|
+
try {
|
|
40
|
+
throw new Error("");
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
var error = e;
|
|
44
|
+
if (!error.stack)
|
|
45
|
+
return undefined;
|
|
46
|
+
var stackLines = error.stack.split('\n');
|
|
47
|
+
if (stackLines.length < 4)
|
|
48
|
+
return undefined;
|
|
49
|
+
// Here we have something like:
|
|
50
|
+
// at file:///Users/johan/Projets/jopijs-workspace/__tests/jopi-ui-sample/dist/mod_sample/routes/tests/test3.page.js:4:1
|
|
51
|
+
//
|
|
52
|
+
var fileUrl = stackLines[3].trim();
|
|
53
|
+
var idx = fileUrl.indexOf("file://");
|
|
54
|
+
fileUrl = fileUrl.substring(idx);
|
|
55
|
+
idx = fileUrl.lastIndexOf(":");
|
|
56
|
+
fileUrl = fileUrl.substring(0, idx);
|
|
57
|
+
idx = fileUrl.lastIndexOf(":");
|
|
58
|
+
if (idx !== -1)
|
|
59
|
+
fileUrl = fileUrl.substring(0, idx);
|
|
60
|
+
return fileUrl;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export var PriorityLevel;
|
|
64
|
+
(function (PriorityLevel) {
|
|
65
|
+
PriorityLevel[PriorityLevel["veryLow"] = -200] = "veryLow";
|
|
66
|
+
PriorityLevel[PriorityLevel["low"] = -100] = "low";
|
|
67
|
+
PriorityLevel[PriorityLevel["default"] = 0] = "default";
|
|
68
|
+
PriorityLevel[PriorityLevel["high"] = 100] = "high";
|
|
69
|
+
PriorityLevel[PriorityLevel["veryHigh"] = 200] = "veryHigh";
|
|
70
|
+
})(PriorityLevel || (PriorityLevel = {}));
|
|
71
|
+
export function sortByPriority(values) {
|
|
72
|
+
if (values === undefined)
|
|
73
|
+
return undefined;
|
|
74
|
+
values.sort(function (a, b) {
|
|
75
|
+
if (a.priority < b.priority)
|
|
76
|
+
return -1;
|
|
77
|
+
if (a.priority > b.priority)
|
|
78
|
+
return 1;
|
|
79
|
+
return 0;
|
|
80
|
+
});
|
|
81
|
+
return values.map(function (v) { return v.value; });
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Allows avoiding calling a function before n-milliseconds is elapsed.
|
|
85
|
+
*/
|
|
86
|
+
var DontCallBeforeElapsed = /** @class */ (function () {
|
|
87
|
+
function DontCallBeforeElapsed(requireMs) {
|
|
88
|
+
if (requireMs === void 0) { requireMs = 1000; }
|
|
89
|
+
this.requireMs = requireMs;
|
|
90
|
+
this.lastTime = 0;
|
|
91
|
+
}
|
|
92
|
+
DontCallBeforeElapsed.prototype.check = function () {
|
|
93
|
+
var now = Date.now();
|
|
94
|
+
if (now - this.lastTime < this.requireMs)
|
|
95
|
+
return false;
|
|
96
|
+
this.lastTime = now;
|
|
97
|
+
return true;
|
|
98
|
+
};
|
|
99
|
+
return DontCallBeforeElapsed;
|
|
100
|
+
}());
|
|
101
|
+
export { DontCallBeforeElapsed };
|