adaptform 2.0.5 → 2.1.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.
package/dist/index.mjs CHANGED
@@ -18,8 +18,9 @@ var Field = class {
18
18
  this._valueClear = null;
19
19
  this.isValid = null;
20
20
  }
21
+ this.isTouched = false;
21
22
  }
22
- // ========== Геттеры/сеттеры ==========
23
+ // ========== Getters and setters ==========
23
24
  get plugins() {
24
25
  return [...this.options.plugins ?? []].sort((a, b) => {
25
26
  return (a.pluginOptions?.priority ?? 0) - (b.pluginOptions?.priority ?? 0);
@@ -29,13 +30,26 @@ var Field = class {
29
30
  return this.fieldType.options;
30
31
  }
31
32
  set options(options) {
32
- let cur_options = this.fieldType.options;
33
- this.fieldType.options = Object.assign(cur_options, options);
33
+ const currentOptions = this.fieldType.options;
34
+ this.fieldType.options = Object.assign(currentOptions, options);
34
35
  }
35
36
  get rawValue() {
36
37
  return this._rawValue;
37
38
  }
38
39
  set rawValue(input) {
40
+ this.setRawValue(input);
41
+ }
42
+ setRawValue(input, validate = true) {
43
+ this.assignRawValue(input);
44
+ this._errors = [];
45
+ this.isTouched = true;
46
+ if (validate) {
47
+ this.checkAndSetValid();
48
+ } else {
49
+ this.isValid = null;
50
+ }
51
+ }
52
+ assignRawValue(input) {
39
53
  let rawValue = input;
40
54
  for (const plugin of this.plugins) {
41
55
  if (plugin.toRawValue) {
@@ -50,9 +64,6 @@ var Field = class {
50
64
  }
51
65
  this._rawValue = rawValue;
52
66
  this._valueClear = this.fieldType.cast(valueClear);
53
- this._errors = [];
54
- this.isTouched = true;
55
- this.checkAndSetValid();
56
67
  }
57
68
  get errors() {
58
69
  return this._errors;
@@ -71,7 +82,7 @@ var Field = class {
71
82
  get valueClear() {
72
83
  return this._valueClear;
73
84
  }
74
- // ========== Валидация ==========
85
+ // ========== Validation ==========
75
86
  isRequired(form) {
76
87
  let isRequired;
77
88
  if (typeof this.options.isRequired === "function") {
@@ -121,55 +132,61 @@ var Field = class {
121
132
  get isEmpty() {
122
133
  let isEmpty = false;
123
134
  if (this._rawValue === null || this._rawValue === void 0) isEmpty = true;
124
- else if (this._rawValue === "") isEmpty = true;
135
+ else if (typeof this._rawValue === "string" && this._rawValue.trim() === "") isEmpty = true;
125
136
  else if (Array.isArray(this._rawValue) && this._rawValue.length === 0) isEmpty = true;
126
137
  return isEmpty;
127
138
  }
128
- // ========== Вспомогательные методы ==========
139
+ // ========== Helper methods ==========
129
140
  reset() {
130
141
  if (this.defaultValue !== null && this.defaultValue !== void 0) {
131
- this.rawValue = this.defaultValue;
142
+ this.assignRawValue(this.defaultValue);
132
143
  } else {
133
144
  this._rawValue = null;
134
145
  this._valueClear = null;
135
- this.isValid = null;
136
146
  }
137
147
  this._errors = [];
148
+ this.isValid = null;
138
149
  this.isTouched = false;
139
150
  }
140
151
  };
141
152
 
153
+ // src/core/fields/arrayUtils.ts
154
+ function isValidArrayIndex(index, length) {
155
+ return Number.isInteger(index) && index >= 0 && index < length;
156
+ }
157
+
142
158
  // src/core/fields/ArrayField.ts
143
159
  var ArrayField = class {
144
160
  constructor(factory, options = {}, initial = []) {
145
161
  this.factory = factory;
146
162
  this._items = [];
147
163
  this._errors = [];
164
+ this._hasValidationResult = false;
148
165
  this.isTouched = false;
149
166
  this.options = {
150
167
  isRequired: true,
151
168
  messages: {},
152
169
  ...options
153
170
  };
154
- this._items = initial.map((v) => this.factory(v));
171
+ this._items = initial.map((value) => this.factory(value));
155
172
  this.checkValid();
156
173
  }
157
174
  // ===== value =====
158
175
  set itemsValue(items) {
159
176
  this.clear();
160
- for (const i of items) {
161
- this.add(i, false);
177
+ for (const item of items) {
178
+ this.add(item, false);
162
179
  }
163
180
  this.checkValid();
164
181
  }
165
182
  get itemsValue() {
166
- return this._items.map((i) => i.valueClear);
183
+ return this._items.map((item) => item.valueClear);
167
184
  }
168
185
  get items() {
169
186
  return this._items;
170
187
  }
171
188
  // ===== actions =====
172
- add(value, force_check) {
189
+ add(value, force_check = true) {
173
190
  const field = this.factory(value);
174
191
  this.isTouched = true;
175
192
  this._items.push(field);
@@ -177,6 +194,7 @@ var ArrayField = class {
177
194
  return field;
178
195
  }
179
196
  remove(index) {
197
+ if (!isValidArrayIndex(index, this._items.length)) return;
180
198
  this._items.splice(index, 1);
181
199
  this.checkValid();
182
200
  }
@@ -195,6 +213,7 @@ var ArrayField = class {
195
213
  return isRequired;
196
214
  }
197
215
  checkValid(form) {
216
+ this._hasValidationResult = true;
198
217
  this._errors = [];
199
218
  if (this.isRequired(form) && this._items.length === 0) {
200
219
  this._errors.push(
@@ -220,7 +239,7 @@ var ArrayField = class {
220
239
  if (!ok) valid = false;
221
240
  }
222
241
  if (this.options.validate) {
223
- const values = this._items.map((i) => i.valueClear);
242
+ const values = this._items.map((item) => item.valueClear);
224
243
  const result = this.options.validate(values, form);
225
244
  if (result === false) {
226
245
  this._errors.push(
@@ -239,8 +258,9 @@ var ArrayField = class {
239
258
  return this.checkValid(form);
240
259
  }
241
260
  get isValid() {
261
+ if (!this._hasValidationResult) return false;
242
262
  if (this._errors.length > 0) return false;
243
- return this._items.every((i) => i.isValid === true);
263
+ return this._items.every((item) => item.isValid === true);
244
264
  }
245
265
  get error() {
246
266
  return this._errors[0] ?? "";
@@ -248,16 +268,19 @@ var ArrayField = class {
248
268
  set error(message) {
249
269
  if (message) {
250
270
  this._errors = [message];
271
+ this._hasValidationResult = true;
251
272
  } else {
252
273
  this._errors = [];
274
+ this._hasValidationResult = false;
253
275
  }
254
276
  }
255
277
  get errors() {
256
278
  return this._errors;
257
279
  }
258
280
  reset() {
259
- this._items.forEach((i) => i.reset());
281
+ this._items.forEach((item) => item.reset());
260
282
  this._errors = [];
283
+ this._hasValidationResult = false;
261
284
  this.isTouched = false;
262
285
  }
263
286
  };
@@ -269,38 +292,45 @@ var ArrayFormField = class {
269
292
  this.options = options;
270
293
  this._forms = [];
271
294
  this._errors = [];
295
+ this._hasValidationResult = false;
272
296
  this.isTouched = false;
273
297
  this._forms = initial.map((data) => {
274
298
  const form = new this.FormConstructor();
275
- form.fields = data;
299
+ form.setFields(data, false);
276
300
  return form;
277
301
  });
278
302
  this.checkValid();
279
303
  }
280
304
  // ===== value =====
281
305
  set forms(forms) {
282
- this.clear();
283
- for (const f of forms) {
284
- this.add(f, false);
306
+ this.setForms(forms);
307
+ }
308
+ setForms(forms, validate = true) {
309
+ this._forms = [];
310
+ for (const formData of forms) {
311
+ this.add(formData, false);
285
312
  }
286
- this.checkValid();
313
+ if (validate) this.checkValid();
287
314
  }
288
315
  get forms() {
289
316
  return this._forms;
290
317
  }
291
318
  get formsFieldsValue() {
292
- return this._forms.map((i) => i.fieldsValue);
319
+ return this._forms.map((form) => form.fieldsValue);
293
320
  }
294
321
  // ===== actions =====
295
- add(data, force_check) {
322
+ add(data, force_check = true) {
296
323
  const form = new this.FormConstructor();
297
- if (data) form.fields = data;
324
+ if (data !== void 0 && data !== null) {
325
+ form.setFields(data, false);
326
+ }
298
327
  this.isTouched = true;
299
328
  this._forms.push(form);
300
329
  if (force_check) this.checkValid();
301
330
  return form;
302
331
  }
303
332
  remove(index) {
333
+ if (!isValidArrayIndex(index, this._forms.length)) return;
304
334
  this._forms.splice(index, 1);
305
335
  this.checkValid();
306
336
  }
@@ -309,8 +339,9 @@ var ArrayFormField = class {
309
339
  this.checkValid();
310
340
  }
311
341
  reset() {
312
- this._forms.forEach((f) => f.reset());
342
+ this._forms.forEach((form) => form.reset());
313
343
  this._errors = [];
344
+ this._hasValidationResult = false;
314
345
  this.isTouched = false;
315
346
  }
316
347
  // ===== validation =====
@@ -324,8 +355,9 @@ var ArrayFormField = class {
324
355
  return isRequired;
325
356
  }
326
357
  checkValid(form) {
358
+ this._hasValidationResult = true;
327
359
  this._errors = [];
328
- if (this.isRequired(form) && this.forms.length === 0) {
360
+ if (this.isRequired(form) && this._forms.length === 0) {
329
361
  this._errors.push(
330
362
  this.options.messages?.isRequired ?? "\u0414\u043E\u0431\u0430\u0432\u044C\u0442\u0435 \u0445\u043E\u0442\u044F \u0431\u044B \u043E\u0434\u0438\u043D \u044D\u043B\u0435\u043C\u0435\u043D\u0442"
331
363
  );
@@ -344,12 +376,12 @@ var ArrayFormField = class {
344
376
  return false;
345
377
  }
346
378
  let valid = true;
347
- for (const form2 of this.forms) {
348
- const ok = form2.checkValid(form2);
379
+ for (const nestedForm of this._forms) {
380
+ const ok = nestedForm.checkValid(nestedForm);
349
381
  if (!ok) valid = false;
350
382
  }
351
383
  if (this.options.validate) {
352
- const result = this.options.validate(this.forms, form);
384
+ const result = this.options.validate(this._forms, form);
353
385
  if (result === false) {
354
386
  this._errors.push(
355
387
  this.options.messages?.validate ?? "\u041E\u0448\u0438\u0431\u043A\u0430 \u0432\u0430\u043B\u0438\u0434\u0430\u0446\u0438\u0438"
@@ -367,8 +399,9 @@ var ArrayFormField = class {
367
399
  return this.checkValid(form);
368
400
  }
369
401
  get isValid() {
402
+ if (!this._hasValidationResult) return false;
370
403
  if (this._errors.length > 0) return false;
371
- return this._forms.every((i) => i.checkValid() === true);
404
+ return this._forms.every((form) => form.isValid);
372
405
  }
373
406
  get errors() {
374
407
  return this._errors;
@@ -379,8 +412,10 @@ var ArrayFormField = class {
379
412
  set error(message) {
380
413
  if (message) {
381
414
  this._errors = [message];
415
+ this._hasValidationResult = true;
382
416
  } else {
383
417
  this._errors = [];
418
+ this._hasValidationResult = false;
384
419
  }
385
420
  }
386
421
  };
@@ -393,19 +428,19 @@ var ErrorsSchema = class _ErrorsSchema {
393
428
  this._valueTransformers = [];
394
429
  }
395
430
  /**
396
- * Добавляет статическое правило - точное соответствие ключа ошибки
397
- * @param errorKey - точный ключ ошибки из ответа сервера
398
- * @param fieldName - имя поля в форме или функция для динамического определения
431
+ * Add a static rule that matches an exact error key.
432
+ * @param errorKey - Exact error key returned by the server.
433
+ * @param fieldName - Form field name or a function that resolves it dynamically.
399
434
  */
400
435
  staticKey(errorKey, fieldName) {
401
436
  this._staticRules.set(errorKey, fieldName);
402
437
  return this;
403
438
  }
404
439
  /**
405
- * Добавляет динамическое правило с регулярным выражением
406
- * @param pattern - регулярное выражение для сопоставления ключа ошибки
407
- * @param mapping - имя поля или функция для извлечения имени поля из совпадения
408
- * @param options - дополнительные опции (приоритет и т.д.)
440
+ * Add a dynamic rule using a regular expression.
441
+ * @param pattern - Regular expression used to match an error key.
442
+ * @param mapping - Field name or function that derives it from the match.
443
+ * @param options - Additional options, such as rule priority.
409
444
  */
410
445
  dynamicKey(pattern, mapping, options) {
411
446
  this._dynamicRules.push({
@@ -417,22 +452,22 @@ var ErrorsSchema = class _ErrorsSchema {
417
452
  return this;
418
453
  }
419
454
  /**
420
- * Устанавливает обработчик для ошибок, которые не подошли ни под одно правило
455
+ * Set a handler for errors that do not match any rule.
421
456
  */
422
457
  fallback(handler) {
423
458
  this._fallbackHandler = handler;
424
459
  return this;
425
460
  }
426
461
  /**
427
- * Добавляет трансформер для значений ошибок
428
- * Полезно для нормализации сообщений (например, если сервер возвращает массив ошибок)
462
+ * Add a transformer for error values.
463
+ * Useful for normalizing messages, such as server responses containing arrays.
429
464
  */
430
465
  transformValue(transformer) {
431
466
  this._valueTransformers.push(transformer);
432
467
  return this;
433
468
  }
434
469
  /**
435
- * Быстрый метод для создания схемы из простого объекта маппинга
470
+ * Create a schema from a simple mapping object.
436
471
  */
437
472
  static fromObject(mapping) {
438
473
  const schema = new _ErrorsSchema();
@@ -442,24 +477,35 @@ var ErrorsSchema = class _ErrorsSchema {
442
477
  return schema;
443
478
  }
444
479
  /**
445
- * Создает схему для массива однотипных форм
480
+ * Create a schema for an array of similarly structured forms.
446
481
  */
447
482
  static forArray(itemSchema, arrayFieldName, indexExtractor) {
448
483
  const schema = new _ErrorsSchema();
484
+ for (const transformer of itemSchema._valueTransformers) {
485
+ schema.transformValue(transformer);
486
+ }
487
+ const escapedArrayFieldName = arrayFieldName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
488
+ const indexPattern = indexExtractor ? "(.+?)" : "(?:\\[(\\d+)\\]|\\.(\\d+))";
449
489
  schema.dynamicKey(
450
- new RegExp(`^${arrayFieldName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\[(\\d+)\\]\\.(.+)$`),
451
- (match) => {
452
- const index = match[1];
453
- const fieldName = match[2];
454
- return `${arrayFieldName}.${index}.${fieldName}`;
490
+ new RegExp(`^${escapedArrayFieldName}${indexPattern}\\.(.+)$`),
491
+ (match, value) => {
492
+ const sourceKey = match[0];
493
+ const index = indexExtractor ? indexExtractor(sourceKey) : Number(match[1] ?? match[2]);
494
+ if (!Number.isInteger(index) || index < 0) {
495
+ return "";
496
+ }
497
+ const fieldPath = match[indexExtractor ? 2 : 3];
498
+ const itemMapping = itemSchema.findMapping(fieldPath, value);
499
+ const mappedFieldPath = itemMapping ? typeof itemMapping === "function" ? itemMapping(value) : itemMapping : fieldPath;
500
+ return `${arrayFieldName}.${index}.${mappedFieldPath}`;
455
501
  },
456
502
  { priority: 100 }
457
503
  );
458
504
  return schema;
459
505
  }
460
506
  /**
461
- * Основной метод парсинга ошибок с поддержкой трансформеров
462
- * Поддерживает вложенные структуры через точечную нотацию
507
+ * Parse errors while applying configured value transformers.
508
+ * Supports nested structures using dot notation.
463
509
  */
464
510
  parseErrors(errors, prefix = "") {
465
511
  const result = {};
@@ -487,17 +533,12 @@ var ErrorsSchema = class _ErrorsSchema {
487
533
  } else {
488
534
  result[mapping] = typeof transformedValue === "string" ? transformedValue : JSON.stringify(transformedValue);
489
535
  }
490
- } else if (this._fallbackHandler) {
491
- const fieldName = this._fallbackHandler(fullKey, transformedValue);
492
- if (fieldName) {
493
- result[fieldName] = typeof transformedValue === "string" ? transformedValue : JSON.stringify(transformedValue);
494
- }
495
536
  }
496
537
  }
497
538
  return result;
498
539
  }
499
540
  /**
500
- * Парсит ошибки сервера и возвращает расширенную информацию
541
+ * Parse server errors and return detailed metadata.
501
542
  */
502
543
  parseErrorsDetailed(errors, prefix = "") {
503
544
  const result = {};
@@ -529,7 +570,7 @@ var ErrorsSchema = class _ErrorsSchema {
529
570
  return result;
530
571
  }
531
572
  /**
532
- * Создает схему для вложенной формы
573
+ * Create a schema for a nested form.
533
574
  */
534
575
  nest(prefix) {
535
576
  const nestedSchema = new _ErrorsSchema();
@@ -554,7 +595,7 @@ var ErrorsSchema = class _ErrorsSchema {
554
595
  return nestedSchema;
555
596
  }
556
597
  /**
557
- * Клонирует текущую схему
598
+ * Clone the current schema.
558
599
  */
559
600
  clone() {
560
601
  const cloned = new _ErrorsSchema();
@@ -569,7 +610,7 @@ var ErrorsSchema = class _ErrorsSchema {
569
610
  return cloned;
570
611
  }
571
612
  /**
572
- * Объединяет текущую схему с другой
613
+ * Merge the current schema with another schema.
573
614
  */
574
615
  merge(other) {
575
616
  const merged = this.clone();
@@ -596,7 +637,7 @@ var ErrorsSchema = class _ErrorsSchema {
596
637
  for (const rule of this._dynamicRules) {
597
638
  const match = key.match(rule.pattern);
598
639
  if (match) {
599
- const fieldName = typeof rule.mapping === "function" ? rule.mapping(match) : rule.mapping;
640
+ const fieldName = typeof rule.mapping === "function" ? rule.mapping(match, value) : rule.mapping;
600
641
  return fieldName ? { fieldName, matchedBy: "dynamic" } : null;
601
642
  }
602
643
  }
@@ -614,7 +655,7 @@ var ErrorsSchema = class _ErrorsSchema {
614
655
  const match = key.match(rule.pattern);
615
656
  if (match) {
616
657
  if (typeof rule.mapping === "function") {
617
- const fieldName = rule.mapping(match);
658
+ const fieldName = rule.mapping(match, value);
618
659
  return fieldName;
619
660
  }
620
661
  return rule.mapping;
@@ -654,7 +695,7 @@ var Form = class {
654
695
  isFormValid = false;
655
696
  }
656
697
  }
657
- return isFormValid;
698
+ return isFormValid && Object.keys(this._globalErrors).length === 0;
658
699
  }
659
700
  get fieldsValue() {
660
701
  const data = {};
@@ -671,16 +712,20 @@ var Form = class {
671
712
  return data;
672
713
  }
673
714
  set fields(data) {
715
+ this.setFields(data);
716
+ }
717
+ setFields(data, validate = true) {
674
718
  const fields = this._fields;
675
719
  for (const key of Object.keys(data)) {
676
720
  const field = fields[key];
677
721
  if (field) {
678
- if (field instanceof Field) field.rawValue = data[key];
722
+ if (field instanceof Field) field.setRawValue(data[key], false);
679
723
  else if (field instanceof ArrayField) field.itemsValue = data[key];
680
- else if (field instanceof ArrayFormField) field.forms = data[key];
724
+ else if (field instanceof ArrayFormField) field.setForms(data[key], false);
681
725
  else console.error(`Invalid field "${key}" type`);
682
726
  }
683
727
  }
728
+ if (validate) this.checkValid();
684
729
  }
685
730
  get allErrors() {
686
731
  const errors = {};
@@ -708,7 +753,7 @@ var Form = class {
708
753
  return errors;
709
754
  }
710
755
  /**
711
- * Рекурсивно собирает все ошибки из ArrayFormField
756
+ * Recursively collect all errors from an ArrayFormField.
712
757
  */
713
758
  collectArrayFormErrors(arrayField) {
714
759
  const allErrors = [];
@@ -728,19 +773,30 @@ var Form = class {
728
773
  return { ...this._globalErrors };
729
774
  }
730
775
  set errors(errors) {
776
+ this.clearErrorsRecursively();
731
777
  const fields = this._fields;
732
- this._globalErrors = {};
733
- for (const key of Object.keys(fields)) {
734
- fields[key].error = null;
735
- }
736
778
  const parsedErrors = this.errorsShema.parseErrors(errors);
737
779
  for (const [fieldName, errorMessage] of Object.entries(parsedErrors)) {
738
780
  this.applyErrorToField(fieldName, errorMessage, fields, this);
739
781
  }
740
782
  }
783
+ clearErrorsRecursively() {
784
+ this._globalErrors = {};
785
+ for (const field of Object.values(this._fields)) {
786
+ if (field instanceof Field) {
787
+ field.error = null;
788
+ } else if (field instanceof ArrayField) {
789
+ field.error = null;
790
+ for (const item of field.items) item.error = null;
791
+ } else if (field instanceof ArrayFormField) {
792
+ field.error = null;
793
+ for (const nestedForm of field.forms) nestedForm.clearErrorsRecursively();
794
+ }
795
+ }
796
+ }
741
797
  /**
742
- * Применяет ошибку к соответствующему полю
743
- * Поддерживает вложенные поля через точечную нотацию
798
+ * Apply an error to the corresponding field.
799
+ * Supports nested fields using dot notation.
744
800
  */
745
801
  applyErrorToField(fieldPath, errorMessage, fields, targetForm) {
746
802
  if (!targetForm) {
@@ -807,7 +863,7 @@ var Form = class {
807
863
  }
808
864
  return false;
809
865
  }
810
- // Проверить, валидна ли форма
866
+ // Check whether the form is valid.
811
867
  get isValid() {
812
868
  const fields = this._fields;
813
869
  for (const key of Object.keys(fields)) {
@@ -815,32 +871,50 @@ var Form = class {
815
871
  }
816
872
  return Object.keys(this._globalErrors).length === 0;
817
873
  }
818
- // Получить все значения в виде FormData (для отправки на сервер)
874
+ // Serialize form values for multipart requests.
819
875
  toFormData() {
820
876
  const formData = new FormData();
821
877
  const data = this.fieldsValue;
822
878
  for (const [key, value] of Object.entries(data)) {
823
- if (value instanceof Date) {
879
+ if (value === null || value === void 0) continue;
880
+ if (typeof Blob !== "undefined" && value instanceof Blob) {
881
+ formData.append(key, value);
882
+ } else if (value instanceof Date) {
824
883
  formData.append(key, value.toISOString());
825
- } else if (value !== null && value !== void 0) {
884
+ } else if (typeof value === "object") {
885
+ const serialized = JSON.stringify(value);
886
+ if (serialized !== void 0) formData.append(key, serialized);
887
+ } else {
826
888
  formData.append(key, String(value));
827
889
  }
828
890
  }
829
891
  return formData;
830
892
  }
831
- // Получить все значения в виде JSON
893
+ // Get all values in JSON-compatible form.
832
894
  toJSON() {
833
- const data = this.fieldsValue;
834
895
  const json = {};
835
- for (const [key, value] of Object.entries(data)) {
836
- if (value instanceof Date) {
837
- json[key] = value.toISOString();
838
- } else {
839
- json[key] = value;
840
- }
896
+ for (const [key, value] of Object.entries(this.fieldsValue)) {
897
+ json[key] = this.serializeJsonValue(value);
841
898
  }
842
899
  return json;
843
900
  }
901
+ serializeJsonValue(value) {
902
+ if (value instanceof Date) {
903
+ return value.toISOString();
904
+ }
905
+ if (Array.isArray(value)) {
906
+ return value.map((item) => this.serializeJsonValue(item));
907
+ }
908
+ if (value !== null && typeof value === "object") {
909
+ const prototype = Object.getPrototypeOf(value);
910
+ if (prototype === Object.prototype || prototype === null) {
911
+ return Object.fromEntries(
912
+ Object.entries(value).map(([key, nestedValue]) => [key, this.serializeJsonValue(nestedValue)])
913
+ );
914
+ }
915
+ }
916
+ return value;
917
+ }
844
918
  };
845
919
 
846
920
  // src/core/plugins/FieldPlugin.ts
@@ -860,13 +934,13 @@ var MaskPlugin = class extends BasePlugin {
860
934
  this.maskParts = [];
861
935
  this.config = config;
862
936
  }
863
- init(field) {
937
+ init(_field) {
864
938
  this.parseMask();
865
939
  }
866
- toRawValue(value, field) {
940
+ toRawValue(value, _field) {
867
941
  return this.applyMask(value);
868
942
  }
869
- toValueClear(value, field) {
943
+ toValueClear(value, _field) {
870
944
  return this.removeMask(value);
871
945
  }
872
946
  parseMask() {
@@ -1065,8 +1139,12 @@ var StringType = class extends FieldType {
1065
1139
  this.options.messages?.maxLength ?? `\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u0430\u044F \u0434\u043B\u0438\u043D\u0430 ${this.options.maxLength} \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432`
1066
1140
  );
1067
1141
  }
1068
- if (this.options.pattern != null && !this.options.pattern.test(value)) {
1069
- errors.push(this.options.messages?.pattern ?? "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0444\u043E\u0440\u043C\u0430\u0442");
1142
+ if (this.options.pattern != null) {
1143
+ const { source, flags } = this.options.pattern;
1144
+ const stablePattern = new RegExp(source, flags.replace(/[gy]/g, ""));
1145
+ if (!stablePattern.test(value)) {
1146
+ errors.push(this.options.messages?.pattern ?? "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0444\u043E\u0440\u043C\u0430\u0442");
1147
+ }
1070
1148
  }
1071
1149
  return errors;
1072
1150
  }
@@ -1079,15 +1157,21 @@ var StringType = class extends FieldType {
1079
1157
  var NumberType = class extends FieldType {
1080
1158
  cast(rawValue) {
1081
1159
  if (rawValue === null || rawValue === void 0) return null;
1082
- if (typeof rawValue === "number" && !isNaN(rawValue)) return rawValue;
1160
+ if (typeof rawValue === "number") return Number.isFinite(rawValue) ? rawValue : null;
1083
1161
  if (typeof rawValue === "string") {
1084
- const num = Number(rawValue);
1085
- return isNaN(num) ? null : num;
1162
+ const normalized = rawValue.trim();
1163
+ if (normalized.length === 0) return null;
1164
+ const num = Number(normalized);
1165
+ return Number.isFinite(num) ? num : null;
1086
1166
  }
1087
1167
  return null;
1088
1168
  }
1089
1169
  validate(value) {
1090
1170
  const errors = [];
1171
+ if (!Number.isFinite(value)) {
1172
+ errors.push(this.options.messages?.invalid ?? "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043A\u043E\u043D\u0435\u0447\u043D\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C");
1173
+ return errors;
1174
+ }
1091
1175
  if (!Number.isInteger(value)) {
1092
1176
  errors.push(this.options.messages?.invalid ?? "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0446\u0435\u043B\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C");
1093
1177
  }
@@ -1132,7 +1216,7 @@ var DecimalType = class extends FieldType {
1132
1216
  if (typeof rawValue === "string") {
1133
1217
  return this.castString(rawValue);
1134
1218
  }
1135
- if (typeof rawValue === "number" && !isNaN(rawValue)) {
1219
+ if (typeof rawValue === "number" && Number.isFinite(rawValue)) {
1136
1220
  return rawValue;
1137
1221
  }
1138
1222
  return null;
@@ -1148,13 +1232,13 @@ var DecimalType = class extends FieldType {
1148
1232
  }
1149
1233
  validate(value) {
1150
1234
  const errors = [];
1151
- value = typeof value === "number" ? this.numberToString(value) : value;
1235
+ value = typeof value === "number" ? String(value) : value;
1152
1236
  if (!this.isValidNumberString(value)) {
1153
1237
  errors.push(this.options.messages?.invalid ?? "\u041F\u0440\u0438\u043C\u0435\u0440: 1.00");
1154
1238
  return errors;
1155
1239
  }
1156
- const maxDigits = this.options.maxDigits || 8;
1157
- const decimalPlaces = this.options.decimalPlaces || 2;
1240
+ const maxDigits = this.options.maxDigits ?? 8;
1241
+ const decimalPlaces = this.options.decimalPlaces ?? 2;
1158
1242
  const maxIntDigits = maxDigits - decimalPlaces;
1159
1243
  const isNegative = value.startsWith("-");
1160
1244
  const normalizedValue = isNegative ? value.substring(1) : value;
@@ -1228,10 +1312,6 @@ var DecimalType = class extends FieldType {
1228
1312
  if (dotCount > 1) return false;
1229
1313
  return pattern.test(value);
1230
1314
  }
1231
- numberToString(value) {
1232
- const decimalPlaces = this.options.decimalPlaces;
1233
- return value.toFixed(decimalPlaces);
1234
- }
1235
1315
  getTypeName() {
1236
1316
  return "\u0434\u0435\u0441\u044F\u0442\u0438\u0447\u043D\u043E\u0435 \u0447\u0438\u0441\u043B\u043E";
1237
1317
  }
@@ -1308,7 +1388,7 @@ var DateType = class extends FieldType {
1308
1388
  getTypeName() {
1309
1389
  return this.options.isDatetime ? "\u0434\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043C\u044F" : "\u0434\u0430\u0442\u0430";
1310
1390
  }
1311
- // Сравнение дат с учётом времени
1391
+ // Compare dates with optional time precision.
1312
1392
  compareDates(value, boundary, type) {
1313
1393
  if (this.options.isDatetime) {
1314
1394
  if (type === "min") {
@@ -1331,6 +1411,6 @@ var DateType = class extends FieldType {
1331
1411
  }
1332
1412
  };
1333
1413
 
1334
- export { ArrayField, ArrayFormField, BasePlugin, BooleanType, DateType, DecimalType, Field, FieldType, Form, MaskPlugin, NumberType, StringType };
1414
+ export { ArrayField, ArrayFormField, BasePlugin, BooleanType, DateType, DecimalType, DefaultErrorsSchema, ErrorsSchema, Field, FieldType, Form, MaskPlugin, NumberType, StringType };
1335
1415
  //# sourceMappingURL=index.mjs.map
1336
1416
  //# sourceMappingURL=index.mjs.map