@medyll/idae-machine 0.123.0 → 0.125.0

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.
Files changed (36) hide show
  1. package/dist/form/CreateUpdate.svelte +2 -1
  2. package/dist/index.d.ts +18 -11
  3. package/dist/index.js +18 -11
  4. package/dist/main/machine/IDbCollection.d.ts +71 -0
  5. package/dist/main/machine/IDbCollection.js +102 -0
  6. package/dist/main/machine/IDbCollectionFieldForge.d.ts +42 -0
  7. package/dist/main/machine/IDbCollectionFieldForge.js +74 -0
  8. package/dist/main/machine/IDbCollectionFieldValues.d.ts +57 -0
  9. package/dist/main/machine/IDbCollectionFieldValues.js +82 -0
  10. package/dist/main/machine/IDbCollectionValues.d.ts +78 -0
  11. package/dist/main/machine/IDbCollectionValues.js +203 -0
  12. package/dist/main/machine/IDbError.d.ts +6 -0
  13. package/dist/main/machine/IDbError.js +61 -0
  14. package/dist/main/machine/IDbFormValidate.d.ts +55 -0
  15. package/dist/main/machine/IDbFormValidate.js +183 -0
  16. package/dist/main/machine/IDbValidationError.d.ts +19 -0
  17. package/dist/main/machine/IDbValidationError.js +24 -0
  18. package/dist/main/machineDb.d.ts +18 -222
  19. package/dist/main/machineDb.js +60 -653
  20. package/dist/main/machineForge.d.ts +57 -0
  21. package/dist/main/machineForge.js +105 -0
  22. package/dist/{form → ui}/CollectionButton.svelte +2 -2
  23. package/dist/{form → ui}/CollectionButton.svelte.d.ts +1 -1
  24. package/dist/{form → ui}/CollectionFks.svelte +3 -5
  25. package/dist/{form → ui}/CollectionList.svelte +1 -1
  26. package/dist/{form → ui}/CollectionListMenu.svelte +3 -2
  27. package/package.json +3 -3
  28. package/dist/form/DataList.svelte +0 -60
  29. package/dist/form/DataList.svelte.d.ts +0 -10
  30. /package/dist/{form → ui}/CollectionFieldGuess.svelte +0 -0
  31. /package/dist/{form → ui}/CollectionFieldGuess.svelte.d.ts +0 -0
  32. /package/dist/{form → ui}/CollectionFks.svelte.d.ts +0 -0
  33. /package/dist/{form → ui}/CollectionList.svelte.d.ts +0 -0
  34. /package/dist/{form → ui}/CollectionListMenu.svelte.d.ts +0 -0
  35. /package/dist/{form → ui}/CollectionReverseFks.svelte +0 -0
  36. /package/dist/{form → ui}/CollectionReverseFks.svelte.d.ts +0 -0
@@ -1,7 +1,10 @@
1
1
  /*
2
2
  path: D:\boulot\python\wollama\src\lib\db\dbFields.ts
3
3
  */
4
- import { schemeModel } from '../db/dbSchema.js';
4
+ import { schemeModel } from "../db/dbSchema.js";
5
+ import { IDbCollection } from "./machine/IDbCollection.js";
6
+ import { IDbError } from "./machine/IDbError.js";
7
+ import { MachineForge } from "./machineForge.js";
5
8
  export var enumPrimitive;
6
9
  (function (enumPrimitive) {
7
10
  enumPrimitive["id"] = "id";
@@ -23,29 +26,7 @@ export var TplProperties;
23
26
  TplProperties["readonly"] = "readonly";
24
27
  TplProperties["required"] = "required";
25
28
  })(TplProperties || (TplProperties = {}));
26
- const a = 'any(private required readonly)';
27
- /*
28
- renamed from DbCollectionError to IDbErrors
29
- */
30
- class IDbError extends Error {
31
- code;
32
- constructor(message, code) {
33
- super(message);
34
- this.code = code;
35
- this.name = 'DbCollectionError';
36
- }
37
- static throwError(message, code) {
38
- throw new IDbError(message, code);
39
- }
40
- static handleError(error) {
41
- if (error instanceof IDbError) {
42
- console.error(`${error.name}: ${error.message} (Code: ${error.code})`);
43
- }
44
- else {
45
- console.error('Unexpected error:', error);
46
- }
47
- }
48
- }
29
+ const a = "any(private required readonly)";
49
30
  /**
50
31
  * Central class for parsing, introspecting, and extracting metadata from the database schema.
51
32
  * Provides methods to access collections, templates, fields, foreign keys, and type information.
@@ -56,6 +37,7 @@ export class MachineDb {
56
37
  * The database model (schema) used for introspection.
57
38
  */
58
39
  model = schemeModel;
40
+ machineForge = new MachineForge();
59
41
  #idbCollectionsList = {};
60
42
  /**
61
43
  * Create a new IDbBase instance.
@@ -63,6 +45,7 @@ export class MachineDb {
63
45
  */
64
46
  constructor(model) {
65
47
  this.model = model ?? schemeModel;
48
+ this.machineForge = new MachineForge();
66
49
  }
67
50
  /**
68
51
  * Get an IDbCollection instance for a collection name.
@@ -73,30 +56,32 @@ export class MachineDb {
73
56
  }
74
57
  return this.#idbCollectionsList[collection];
75
58
  }
76
- /**
77
- * Public: Get the value of the index field for a given data object.
78
- */
79
- indexValue(collection, data) {
80
- const indexName = this.collection(collection).getIndexName();
81
- return data && typeof data === 'object' && indexName && data[indexName];
82
- }
83
- /**
84
- * Get an IDbCollectionValues instance for a collection name.
85
- */
86
- collectionValues(collection) {
87
- return new IDbCollectionValues(collection, this);
88
- }
89
- /**
90
- * Get an IDbCollectionFieldValues instance for a collection and data.
91
- */
92
- collectionFieldValues(collection, data) {
93
- return new IDbCollectionFieldValues(collection, data, this.collectionValues(collection));
59
+ fks(collection) {
60
+ const fks = this.collection(collection).getModelTemplateFks();
61
+ const out = {};
62
+ if (fks) {
63
+ Object.keys(fks).forEach((collection) => {
64
+ out[collection] = this.parseRawCollection(collection);
65
+ });
66
+ }
67
+ return out;
94
68
  }
95
- /**
96
- * Get an IDbFormValidate instance for a collection name.
97
- */
98
- formValidate(collection) {
99
- return new IDbFormValidate(collection, this);
69
+ reverseFks(targetCollection) {
70
+ const result = {};
71
+ Object.entries(this.model).forEach(([collectionName, collectionModel]) => {
72
+ const template = collectionModel.template;
73
+ if (template && template.fks) {
74
+ Object.entries(template.fks).forEach(([fkName, fkConfig]) => {
75
+ if (fkConfig?.code === targetCollection) {
76
+ if (!result[collectionName]) {
77
+ result[collectionName] = {};
78
+ }
79
+ result[collectionName][fkName] = fkConfig;
80
+ }
81
+ });
82
+ }
83
+ });
84
+ return result;
100
85
  }
101
86
  /**
102
87
  * Parse all fields of a given collection.
@@ -118,37 +103,30 @@ export class MachineDb {
118
103
  * Parse a single field of a collection and return its IDbForge metadata.
119
104
  */
120
105
  parseCollectionFieldName(collection, fieldName) {
121
- const field = this.#getTemplateFieldRule(collection, fieldName);
106
+ const field = this.collection(collection).getFieldRule(fieldName);
122
107
  if (!field) {
123
- IDbError.throwError(`Field ${fieldName} not found in collection ${collection}`, 'FIELD_NOT_FOUND');
108
+ IDbError.throwError(`Field ${fieldName} not found in collection ${collection}`, "FIELD_NOT_FOUND");
124
109
  return undefined;
125
110
  }
126
- const array = this.testIs('array', field);
127
- const object = this.testIs('object', field);
128
- const fk = this.testIs('fk', field);
129
- const primitive = this.testIs('primitive', field);
111
+ const array = this.machineForge.testIs("array", field);
112
+ const object = this.machineForge.testIs("object", field);
113
+ const fk = this.machineForge.testIs("fk", field);
114
+ const primitive = this.machineForge.testIs("primitive", field);
130
115
  const fieldType = array ?? object ?? fk ?? primitive;
131
- return this.forge({ collection, fieldName, ...fieldType });
132
- }
133
- // Toutes ces méthodes sont maintenant dans IDbCollection
134
- #getTemplateFieldRule(collection, fieldName) {
135
- // Utilise la nouvelle API orientée collection
136
- return new IDbCollection(collection, this, this.model).getFieldRule(fieldName);
137
- }
138
- getFkFieldType(string) {
139
- const [collection, field] = string.split('.');
140
- let template = this.#getTemplateFieldRule(collection, field);
141
- return template;
142
- }
143
- getFkTemplateFields(string) {
144
- const [collection, field] = string.split('.');
145
- return this.collection(collection).getTemplate()?.fields;
116
+ return this.machineForge.forge({ collection, fieldName, ...fieldType });
146
117
  }
147
118
  testIs(what, fieldRule) {
148
- const typeMappings = { fk: 'fk-', array: 'array-of-', object: 'object-', primitive: '' };
119
+ const typeMappings = {
120
+ fk: "fk-",
121
+ array: "array-of-",
122
+ object: "object-",
123
+ primitive: "",
124
+ };
149
125
  const prefix = typeMappings[what];
150
- if (what === 'primitive') {
151
- if (!fieldRule.startsWith('array-of-') && !fieldRule.startsWith('object-') && !fieldRule.startsWith('fk-')) {
126
+ if (what === "primitive") {
127
+ if (!fieldRule.startsWith("array-of-") &&
128
+ !fieldRule.startsWith("object-") &&
129
+ !fieldRule.startsWith("fk-")) {
152
130
  return this.is(what, fieldRule);
153
131
  }
154
132
  return undefined;
@@ -163,15 +141,15 @@ export class MachineDb {
163
141
  }
164
142
  extract(type, fieldRule) {
165
143
  function extractAfter(pattern, source) {
166
- const reg = source?.split('(')?.[0];
144
+ const reg = source?.split("(")?.[0];
167
145
  return reg.split(pattern)[1];
168
146
  }
169
147
  function extractArgs(source) {
170
- const [piece, remaining] = source.split('(');
148
+ const [piece, remaining] = source.split("(");
171
149
  if (!remaining)
172
150
  return { piece: piece.trim(), args: undefined };
173
- const [central] = remaining?.split(')');
174
- const args = central?.split(' ');
151
+ const [central] = remaining?.split(")");
152
+ const args = central?.split(" ");
175
153
  return { piece: piece.trim(), args };
176
154
  }
177
155
  let extractedArgs = extractArgs(fieldRule);
@@ -179,594 +157,23 @@ export class MachineDb {
179
157
  let is = extractedArgs?.piece;
180
158
  let fieldArgs = extractedArgs?.args;
181
159
  switch (type) {
182
- case 'array':
183
- fieldType = extractAfter('array-of-', fieldRule);
160
+ case "array":
161
+ fieldType = extractAfter("array-of-", fieldRule);
184
162
  is = is ?? fieldType;
185
163
  break;
186
- case 'object':
187
- fieldType = extractAfter('object-', fieldRule);
164
+ case "object":
165
+ fieldType = extractAfter("object-", fieldRule);
188
166
  is = is ?? fieldType;
189
167
  break;
190
- case 'fk':
191
- fieldType = 'fk-' + extractAfter('fk-', fieldRule);
168
+ case "fk":
169
+ fieldType = "fk-" + extractAfter("fk-", fieldRule);
192
170
  is = extractedArgs?.piece;
193
171
  break;
194
- case 'primitive':
172
+ case "primitive":
195
173
  fieldType = extractedArgs?.piece;
196
174
  is = is ?? fieldType;
197
175
  break;
198
176
  }
199
177
  return { fieldType, fieldRule, fieldArgs, is: type };
200
178
  }
201
- fks(collection) {
202
- let fks = this.collection(collection).getModelTemplateFks();
203
- let out = {};
204
- if (fks) {
205
- Object.keys(fks).forEach((collection) => {
206
- out[collection] = this.parseRawCollection(collection);
207
- });
208
- }
209
- return out;
210
- }
211
- reverseFks(targetCollection) {
212
- const result = {};
213
- Object.entries(this.model).forEach(([collectionName, collectionModel]) => {
214
- const template = collectionModel.template;
215
- if (template && template.fks) {
216
- Object.entries(template.fks).forEach(([fkName, fkConfig]) => {
217
- if (fkConfig?.code === targetCollection) {
218
- if (!result[collectionName]) {
219
- result[collectionName] = {};
220
- }
221
- result[collectionName][fkName] = fkConfig;
222
- }
223
- });
224
- }
225
- });
226
- return result;
227
- }
228
- iterateArrayField(collection, fieldName, data) {
229
- const fieldInfo = this.parseCollectionFieldName(collection, fieldName);
230
- if (fieldInfo?.is !== 'array' || !Array.isArray(data)) {
231
- return [];
232
- }
233
- return data.map((_, idx) => ({ ...fieldInfo, fieldName: `${String(fieldName)}[${idx}]` }));
234
- }
235
- iterateObjectField(collection, fieldName, data) {
236
- const fieldInfo = this.parseCollectionFieldName(collection, fieldName);
237
- if (fieldInfo?.is !== 'object' || typeof data !== 'object' || data === null) {
238
- return [];
239
- }
240
- return Object.keys(data).map((key) => ({ ...fieldInfo, fieldName: `${String(fieldName)}.${key}` }));
241
- }
242
- /**
243
- * Internal helper to construct an IDbForge object from its components.
244
- */
245
- forge({ collection, fieldName, fieldType, fieldRule, fieldArgs, is }) {
246
- return { collection, fieldName, fieldType, fieldRule, fieldArgs, is };
247
- }
248
- }
249
- /* Single collection template relies on IDbBase */
250
- export class IDbCollection {
251
- collection;
252
- #template;
253
- #machineDb;
254
- #model;
255
- constructor(collection, idbBase, model) {
256
- this.collection = collection;
257
- this.#machineDb = idbBase;
258
- this.#model = model[String(collection)];
259
- this.#template = this.#model['template'];
260
- }
261
- get model() {
262
- return this.#model;
263
- }
264
- get fields() {
265
- return this.#template?.fields;
266
- }
267
- getPresentation() {
268
- return this.#template?.presentation;
269
- }
270
- getFieldRule(fieldName) {
271
- return this.fields[String(fieldName)];
272
- }
273
- getTemplate() {
274
- return this.#template;
275
- }
276
- getModelTemplateFks() {
277
- return this.#template?.fks;
278
- }
279
- getIndexName() {
280
- return this.#template?.index;
281
- }
282
- collectionValues() {
283
- return new IDbCollectionValues(this.collection, this.#machineDb);
284
- }
285
- collectionFieldValues(data) {
286
- return new IDbCollectionFieldValues(this.collection, data, this.collectionValues());
287
- }
288
- fieldForge(fieldName, data) {
289
- return new IDbCollectionFieldForge(this.collection, fieldName, data, this.collectionValues());
290
- }
291
- getFormValidate() {
292
- return new IDbFormValidate(this.collection, this.#machineDb);
293
- }
294
- fks() {
295
- return this.#machineDb.fks(this.collection);
296
- }
297
- reverseFks() {
298
- return this.#machineDb.reverseFks(this.collection);
299
- }
300
- }
301
- /**
302
- * IDbCollectionValues
303
- *
304
- * This class provides utilities to display, format, and introspect field values for a given collection, using the schema and provided data.
305
- * It is designed for dynamic UI rendering, presentation logic, and metadata extraction for form generation in schema-driven applications.
306
- *
307
- * Main responsibilities:
308
- * - Holds a reference to the collection name and the schema (IDbBase).
309
- * - Provides methods to format field values according to their type (number, text, array, object, etc.).
310
- * - Supplies presentation logic for displaying records (e.g., presentation string, index value).
311
- * - Offers input attribute generation for forms (inputDataSet).
312
- * - Supports iteration over array/object fields for advanced UI layouts.
313
- * - Enables access to field metadata for validation and rendering.
314
- *
315
- * Usage:
316
- * const values = new IDbCollectionValues('agents');
317
- * const display = values.presentation(agentData); // formatted display string
318
- * const index = values.indexValue(agentData); // index field value
319
- * const formatted = values.format('name', agentData); // formatted field value
320
- * const attrs = values.getInputDataSet('name', agentData); // input attributes for forms
321
- *
322
- * This class is typically used via IDbBase.getCollectionValues for shared instance management.
323
- * @template T - The type of the data object for the collection.
324
- */
325
- export class IDbCollectionValues {
326
- /**
327
- * The IDbBase instance used for schema introspection.
328
- */
329
- idbBase;
330
- /**
331
- * The collection name this instance operates on.
332
- */
333
- collectionName;
334
- /**
335
- * Create a new IDbCollectionValues instance for a given collection.
336
- * @param collectionName The collection name.
337
- */
338
- constructor(collectionName, idbBase) {
339
- this.collectionName = collectionName;
340
- this.idbBase = idbBase ?? new MachineDb();
341
- }
342
- presentation(data) {
343
- try {
344
- this.#checkError(!this.#checkAccess(), 'Access denied', 'ACCESS_DENIED');
345
- const presentation = this.idbBase.collection(this.collectionName).getPresentation();
346
- this.#checkError(!presentation, 'Presentation template not found', 'TEMPLATE_NOT_FOUND');
347
- const fields = presentation.split(' ');
348
- return fields
349
- .map((field) => {
350
- const value = data[field];
351
- return value !== null && value !== undefined ? String(value) : '';
352
- })
353
- .join(' ');
354
- }
355
- catch (error) {
356
- IDbError.handleError(error);
357
- return '';
358
- }
359
- }
360
- /**
361
- * Get the value of the index field for a data object.
362
- * @param data The data object.
363
- * @returns The value of the index field, or null if not found.
364
- */
365
- indexValue(data) {
366
- try {
367
- this.#checkError(!this.#checkAccess(), 'Access denied', 'ACCESS_DENIED');
368
- const indexName = this.idbBase.collection(this.collectionName).getIndexName();
369
- this.#checkError(!indexName, 'Index not found for collection', 'INDEX_NOT_FOUND');
370
- this.#checkError(!(indexName in data), `Index field ${indexName} not found in data`, 'FIELD_NOT_FOUND');
371
- return data[indexName];
372
- }
373
- catch (error) {
374
- IDbError.handleError(error);
375
- return null;
376
- }
377
- }
378
- /**
379
- * Format a field value for display, using the field type and schema.
380
- * @param fieldName The field name.
381
- * @param data The data object.
382
- * @returns The formatted value as a string.
383
- */
384
- format(fieldName, data) {
385
- try {
386
- this.#checkError(!this.#checkAccess(), 'Access denied', 'ACCESS_DENIED');
387
- this.#checkError(!(fieldName in data), `Field ${String(fieldName)} not found in data`, 'FIELD_NOT_FOUND');
388
- const fieldInfo = this.idbBase.parseCollectionFieldName(this.collectionName, fieldName);
389
- this.#checkError(!fieldInfo, `Field ${String(fieldName)} not found in collection`, 'FIELD_NOT_FOUND');
390
- switch (fieldInfo?.fieldType) {
391
- case 'number':
392
- return this.#formatNumberField(data[fieldName]);
393
- case 'text':
394
- case 'text-tiny':
395
- case 'text-short':
396
- case 'text-medium':
397
- case 'text-long':
398
- case 'text-giant':
399
- return this.#formatTextField(data[fieldName], fieldInfo.fieldType);
400
- default:
401
- return String(data[fieldName]);
402
- }
403
- }
404
- catch (error) {
405
- IDbError.handleError(error);
406
- return '';
407
- }
408
- }
409
- /**
410
- * Get a set of data-* attributes for a field, for use in form generation or UI.
411
- * @param fieldName The field name.
412
- * @param data The data object.
413
- * @returns An object with data-* attributes for the field.
414
- */
415
- getInputDataSet(fieldName, data) {
416
- const fieldInfo = this.idbBase.parseCollectionFieldName(this.collectionName, fieldName);
417
- const fieldType = fieldInfo?.fieldType ?? '';
418
- const fieldArgs = fieldInfo?.fieldArgs?.join(' ') ?? '';
419
- const indexName = this.idbBase.collection(this.collectionName).getIndexName();
420
- return {
421
- 'data-collection': this.collectionName,
422
- 'data-collectionId': indexName && data?.[indexName] !== undefined ? String(data?.[indexName]) : '',
423
- 'data-fieldName': String(fieldName),
424
- 'data-fieldType': fieldType,
425
- 'data-fieldArgs': fieldArgs
426
- };
427
- }
428
- /**
429
- * Iterate over an array field and return an array of IDbForge objects for each element.
430
- * @param fieldName The field name.
431
- * @param data The array data.
432
- * @returns An array of IDbForge objects.
433
- */
434
- iterateArrayField(fieldName, data) {
435
- return this.idbBase.iterateArrayField(this.collectionName, fieldName, data);
436
- }
437
- /**
438
- * Iterate over an object field and return an array of IDbForge objects for each property.
439
- * @param fieldName The field name.
440
- * @param data The object data.
441
- * @returns An array of IDbForge objects.
442
- */
443
- iterateObjectField(fieldName, data) {
444
- return this.idbBase.iterateObjectField(this.collectionName, fieldName, data);
445
- }
446
- /**
447
- * Internal: Format a number field for display.
448
- * @param value The number value.
449
- * @returns The formatted string.
450
- */
451
- #formatNumberField(value) {
452
- // Implement number formatting logic here
453
- return value.toString();
454
- }
455
- /**
456
- * Internal: Format a text field for display, with length limits by type.
457
- * @param value The string value.
458
- * @param type The text type (e.g. 'text-short').
459
- * @returns The formatted string.
460
- */
461
- #formatTextField(value, type) {
462
- const lengths = {
463
- 'text-tiny': 10,
464
- 'text-short': 20,
465
- 'text-medium': 30,
466
- 'text-long': 40,
467
- 'text-giant': 50
468
- };
469
- const str = typeof value === 'string' ? value : String(value ?? '');
470
- const maxLength = lengths[type] || str.length;
471
- return str.substring(0, maxLength);
472
- }
473
- /**
474
- * Internal: Check if access is allowed (override for custom logic).
475
- * @returns True if access is allowed.
476
- */
477
- #checkAccess() {
478
- // Implement access check logic here
479
- return true;
480
- }
481
- /**
482
- * Internal: Throw an error if a condition is met.
483
- * @param condition The condition to check.
484
- * @param message The error message.
485
- * @param code The error code.
486
- */
487
- #checkError(condition, message, code) {
488
- if (condition) {
489
- IDbError.throwError(message, code);
490
- }
491
- }
492
- }
493
- export class IDbCollectionFieldValues {
494
- #collection;
495
- #collectionValues;
496
- #data;
497
- /**
498
- * Returns the IDbForge metadata for a given field name.
499
- * @param fieldName The field name to introspect.
500
- */
501
- getForge(fieldName) {
502
- return this.#collectionValues.idbBase.parseCollectionFieldName(this.#collection, String(fieldName));
503
- }
504
- constructor(collection, data, collectionValues) {
505
- this.#collection = collection;
506
- this.#collectionValues = collectionValues ?? new IDbCollectionValues(collection);
507
- this.#data = data;
508
- }
509
- format(fieldName) {
510
- const fieldInfo = this.#collectionValues.idbBase.parseCollectionFieldName(this.#collection, fieldName);
511
- if (fieldInfo?.is === 'array') {
512
- return this.iterateArray(String(fieldName), this.#data);
513
- }
514
- if (fieldInfo?.is === 'object') {
515
- return this.iterateObject(String(fieldName), this.#data);
516
- }
517
- return this.#collectionValues.format(fieldName, this.#data);
518
- }
519
- getInputDataSet(fieldName) {
520
- return this.#collectionValues.getInputDataSet(String(fieldName), this.#data);
521
- }
522
- // renamed from parseCollectionFieldName
523
- // get forge(): IDbForge | undefined {
524
- // return undefined; // Pas de #fieldName dans cette classe, getter non pertinent
525
- // }
526
- iterateArray(fieldName, data) {
527
- return this.#collectionValues.iterateArrayField(fieldName, data);
528
- }
529
- iterateObject(fieldName, data) {
530
- return this.#collectionValues.iterateObjectField(fieldName, data);
531
- }
532
- }
533
- /**
534
- * IDbCollectionFieldForge
535
- *
536
- * This class provides advanced metadata and formatting for a single field of a collection, given a data object.
537
- * It is designed for dynamic UI generation, form rendering, and introspection in schema-driven applications.
538
- *
539
- * Main responsibilities:
540
- * - Holds references to the collection name, field name, and the data object for context.
541
- * - Provides access to the parsed field metadata (IDbForge) for the field, including type, rules, and arguments.
542
- * - Offers formatting utilities for the field value, adapting to type (number, text, array, object, etc.).
543
- * - Supplies input attributes and type hints for form generation (e.g., htmlInputType, inputDataSet).
544
- * - Supports iteration over array/object fields for complex form layouts.
545
- * - Enables extraction of raw data and field arguments for validation and UI logic.
546
- *
547
- * Usage:
548
- * const forge = new IDbCollectionFieldForge('agents', 'name', agentData);
549
- * const formatted = forge.format; // formatted value for display
550
- * const inputType = forge.htmlInputType; // e.g. 'text', 'area', 'email', etc.
551
- * const meta = forge.forge; // IDbForge metadata for the field
552
- *
553
- * This class is typically used via IDbBase.getCollectionFieldForge for shared instance management.
554
- */
555
- export class IDbCollectionFieldForge {
556
- #collection;
557
- #collectionValues;
558
- #fieldName;
559
- #data;
560
- constructor(collection, fieldName, data, collectionValues) {
561
- this.#collection = collection;
562
- this.#collectionValues = collectionValues ?? new IDbCollectionValues(collection);
563
- this.#fieldName = String(fieldName);
564
- this.#data = data;
565
- }
566
- get format() {
567
- return this.#collectionValues.format(String(this.#fieldName), this.#data);
568
- }
569
- get inputDataSet() {
570
- return this.#collectionValues.getInputDataSet(String(this.#fieldName), this.#data);
571
- }
572
- // renamed from parseCollectionFieldName
573
- get forge() {
574
- return this.#collectionValues.idbBase.parseCollectionFieldName(this.#collection, String(this.#fieldName));
575
- }
576
- get fieldArgs() {
577
- return this.forge?.fieldArgs;
578
- }
579
- get fieldType() {
580
- return this.forge?.fieldType;
581
- }
582
- /**
583
- * will return text.inputBase for ['url', 'email', 'number', 'date', 'time', 'datetime', 'phone', 'password']
584
- */
585
- get htmlInputType() {
586
- let variant = this?.fieldType?.split('text-')?.[1] ?? this.fieldType;
587
- if (variant === 'area')
588
- return variant;
589
- if (this.forge?.fieldType?.startsWith('text-'))
590
- return 'text';
591
- if (['url', 'email', 'number', 'date', 'time', 'datetime', 'phone', 'password'].includes(this.forge?.fieldType ?? '')) {
592
- return this.forge?.fieldType?.trim?.() ?? 'text';
593
- }
594
- return 'text';
595
- }
596
- get rawData() {
597
- return this.#data;
598
- }
599
- iterateArray(fieldName, data) {
600
- return this.#collectionValues.iterateArrayField(fieldName, data);
601
- }
602
- iterateObject(fieldName, data) {
603
- return this.#collectionValues.iterateObjectField(fieldName, data);
604
- }
605
- }
606
- class IDbValidationError extends Error {
607
- field;
608
- code;
609
- constructor(field, code, message) {
610
- super(message);
611
- this.field = field;
612
- this.code = code;
613
- this.name = 'IDbValidationError';
614
- }
615
- }
616
- export class IDbFormValidate {
617
- collection;
618
- idbCollections;
619
- constructor(collection, idbCollections) {
620
- this.collection = collection;
621
- this.idbCollections = idbCollections ?? new MachineDb();
622
- }
623
- validateField(fieldName, value) {
624
- try {
625
- const fieldInfo = this.idbCollections.parseCollectionFieldName(this.collection, fieldName);
626
- if (!fieldInfo) {
627
- return { isValid: false, error: `Field ${String(fieldName)} not found in collection` };
628
- }
629
- // Vérification du type
630
- if (!this.#validateType(value, fieldInfo.fieldType)) {
631
- return this.#returnError(fieldName, fieldInfo.fieldType);
632
- }
633
- // Vérification des arguments du champ (required, etc.)
634
- if (fieldInfo.fieldArgs) {
635
- for (const arg of fieldInfo.fieldArgs) {
636
- if (arg === 'required' && (value === undefined || value === null || value === '')) {
637
- return this.#returnError(fieldName, 'required');
638
- }
639
- }
640
- }
641
- // Validations spécifiques selon le type de champ
642
- switch (fieldInfo.fieldType) {
643
- case enumPrimitive.email:
644
- if (!this.validateEmail(value)) {
645
- return this.#returnError(fieldName, fieldInfo.fieldType);
646
- }
647
- break;
648
- case enumPrimitive.url:
649
- if (!this.validateUrl(value)) {
650
- return this.#returnError(fieldName, fieldInfo.fieldType);
651
- }
652
- break;
653
- case enumPrimitive.phone:
654
- if (!this.validatePhone(value)) {
655
- return this.#returnError(fieldName, fieldInfo.fieldType);
656
- }
657
- break;
658
- case enumPrimitive.date:
659
- case enumPrimitive.datetime:
660
- case enumPrimitive.time:
661
- if (!this.validateDateTime(value, fieldInfo.fieldType)) {
662
- return this.#returnError(fieldName, fieldInfo.fieldType);
663
- }
664
- break;
665
- // Ajoutez d'autres cas spécifiques ici
666
- }
667
- return { isValid: true };
668
- }
669
- catch (error) {
670
- if (error instanceof IDbValidationError) {
671
- return { isValid: false, error: error.message };
672
- }
673
- throw error;
674
- }
675
- }
676
- /**
677
- * Validate a single field value for a collection.
678
- * @param fieldName The field name.
679
- * @param value The value to validate.
680
- * @returns True if valid, false otherwise.
681
- */
682
- validateFieldValue(fieldName, value) {
683
- const result = this.validateField(fieldName, value);
684
- return !!result.isValid;
685
- }
686
- validateForm(formData, options = {}) {
687
- const errors = {};
688
- const invalidFields = [];
689
- let isValid = true;
690
- const fields = this.idbCollections.collection(this.collection).getTemplate().fields;
691
- if (!fields) {
692
- return {
693
- isValid: false,
694
- errors: { general: 'Collection template not found' },
695
- invalidFields: ['general']
696
- };
697
- }
698
- for (const [fieldName, fieldRule] of Object.entries(fields)) {
699
- // Ignorer les champs spécifiés dans options.ignoreFields
700
- if (options.ignoreFields && options.ignoreFields.includes(fieldName)) {
701
- continue;
702
- }
703
- const result = this.validateField(fieldName, formData[fieldName]);
704
- if (!result.isValid) {
705
- errors[fieldName] = result.error || 'Invalid field';
706
- invalidFields.push(fieldName);
707
- isValid = false;
708
- }
709
- }
710
- return { isValid, errors, invalidFields };
711
- }
712
- #validateType(value, type) {
713
- switch (type) {
714
- case enumPrimitive.number:
715
- return typeof value === 'number' && !isNaN(value);
716
- case enumPrimitive.boolean:
717
- return typeof value === 'boolean';
718
- case enumPrimitive.text:
719
- case enumPrimitive.email:
720
- case enumPrimitive.url:
721
- case enumPrimitive.phone:
722
- case enumPrimitive.password:
723
- return typeof value === 'string';
724
- case enumPrimitive.date:
725
- case enumPrimitive.datetime:
726
- case enumPrimitive.time:
727
- return value instanceof Date || typeof value === 'string';
728
- case enumPrimitive.any:
729
- return true;
730
- default:
731
- return true; // Pour les types non gérés, on considère que c'est valide
732
- }
733
- }
734
- #returnError(fieldName, enumCode) {
735
- throw new IDbValidationError(String(fieldName), enumCode ?? 'unknown', `Invalid format for field ${String(fieldName)}. Cause "${enumCode}" `);
736
- }
737
- validateEmail(email) {
738
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
739
- return emailRegex.test(email);
740
- }
741
- validateUrl(url) {
742
- try {
743
- new URL(url);
744
- return true;
745
- }
746
- catch {
747
- return false;
748
- }
749
- }
750
- validatePhone(phone) {
751
- // Ceci est un exemple simple. Vous pouvez ajuster selon vos besoins spécifiques
752
- const phoneRegex = /^\+?[\d\s-]{10,}$/;
753
- return phoneRegex.test(phone);
754
- }
755
- validateDateTime(value, type) {
756
- const date = value instanceof Date ? value : new Date(value);
757
- if (isNaN(date.getTime()))
758
- return false;
759
- switch (type) {
760
- case enumPrimitive.date:
761
- return true; // La conversion en Date a déjà validé le format
762
- case enumPrimitive.time:
763
- // Vérifiez si la chaîne contient uniquement l'heure
764
- return /^([01]\d|2[0-3]):([0-5]\d)(:([0-5]\d))?$/.test(value);
765
- case enumPrimitive.datetime:
766
- return true; // La conversion en Date a déjà validé le format
767
- default:
768
- return false;
769
- }
770
- }
771
179
  }
772
- // (fin de fichier)