@macrulez/vue-form-schema 0.1.0 → 0.1.5

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 (51) hide show
  1. package/README.md +707 -410
  2. package/dist/MaskEngine-BqJQYybS.js +233 -0
  3. package/dist/MaskEngine-BwAs2Zb0.cjs +1 -0
  4. package/dist/__tests__/phase3.test.d.ts +2 -0
  5. package/dist/__tests__/phase3.test.d.ts.map +1 -0
  6. package/dist/__tests__/phase4.test.d.ts +2 -0
  7. package/dist/__tests__/phase4.test.d.ts.map +1 -0
  8. package/dist/__tests__/useFieldArray.test.d.ts +2 -0
  9. package/dist/__tests__/useFieldArray.test.d.ts.map +1 -0
  10. package/dist/__tests__/useMultiStepForm.test.d.ts +2 -0
  11. package/dist/__tests__/useMultiStepForm.test.d.ts.map +1 -0
  12. package/dist/core/ConditionEvaluator.d.ts +1 -1
  13. package/dist/core/ConditionEvaluator.d.ts.map +1 -1
  14. package/dist/core/ValidationEngine.d.ts +3 -1
  15. package/dist/core/ValidationEngine.d.ts.map +1 -1
  16. package/dist/core/inferTypes.d.ts +39 -0
  17. package/dist/core/inferTypes.d.ts.map +1 -0
  18. package/dist/core/registry.d.ts +17 -0
  19. package/dist/core/registry.d.ts.map +1 -0
  20. package/dist/core/schemaUtils.d.ts +20 -0
  21. package/dist/core/schemaUtils.d.ts.map +1 -0
  22. package/dist/core/types.d.ts +43 -3
  23. package/dist/core/types.d.ts.map +1 -1
  24. package/dist/core/useFieldArray.d.ts +21 -0
  25. package/dist/core/useFieldArray.d.ts.map +1 -0
  26. package/dist/core/useForm.d.ts.map +1 -1
  27. package/dist/core/useFormDebug.d.ts +29 -0
  28. package/dist/core/useFormDebug.d.ts.map +1 -0
  29. package/dist/core/useFormField.d.ts +18 -0
  30. package/dist/core/useFormField.d.ts.map +1 -0
  31. package/dist/core/useMultiStepForm.d.ts +30 -0
  32. package/dist/core/useMultiStepForm.d.ts.map +1 -0
  33. package/dist/index.cjs +1 -1
  34. package/dist/index.d.ts +14 -2
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +386 -196
  37. package/dist/parsers/valibot.d.ts +20 -0
  38. package/dist/parsers/valibot.d.ts.map +1 -0
  39. package/dist/ui/index.d.ts +2 -0
  40. package/dist/ui/index.d.ts.map +1 -1
  41. package/dist/ui.cjs +1 -1
  42. package/dist/ui.d.ts +114 -18
  43. package/dist/ui.js +360 -193
  44. package/dist/valibot.cjs +1 -0
  45. package/dist/valibot.d.ts +84 -0
  46. package/dist/valibot.js +43 -0
  47. package/dist/yup.d.ts +26 -2
  48. package/dist/zod.d.ts +26 -2
  49. package/package.json +39 -4
  50. package/dist/MaskEngine-D22m29OM.js +0 -157
  51. package/dist/MaskEngine-hd5xHed7.cjs +0 -1
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function p(t){if(!t||t.type!=="object"||!t.entries)throw new Error("[vue-form-schema] parseValibot expects a v.object() schema");return Object.entries(t.entries).map(([r,i])=>o(r,i))}function o(t,r){let i=!0,e=r;(e.type==="optional"||e.type==="nullable"||e.type==="nullish")&&(i=!1,e=e.wrapped??e);const a=u(e),s={type:a,name:t,required:i};return a==="select"&&(s.options=e.options.map(n=>({label:String(n),value:n}))),a==="group"&&e.entries&&(s.fields=Object.entries(e.entries).map(([n,l])=>o(n,l))),s}function u(t){const r=t.type;if(r==="string"&&Array.isArray(t.pipe)&&t.pipe.some(e=>e.type==="email"))return"email";switch(r){case"string":return"text";case"number":return"number";case"boolean":return"checkbox";case"picklist":case"enum":return"select";case"array":return"array";case"object":return"group";default:return"text"}}exports.parseValibot=p;
@@ -0,0 +1,84 @@
1
+ import { Component } from 'vue';
2
+
3
+ declare type AsyncValidatorFn = (value: unknown, values: Record<string, unknown>) => Promise<string | null>;
4
+
5
+ declare interface FieldDefinition {
6
+ type: FieldType;
7
+ /** Dot-path for nested fields, e.g. "address.city" */
8
+ name: string;
9
+ label?: string;
10
+ placeholder?: string;
11
+ defaultValue?: unknown;
12
+ required?: boolean;
13
+ /** Static or dynamic disabled state */
14
+ disabled?: boolean | ((values: Record<string, unknown>) => boolean);
15
+ /** Static or dynamic visibility; string is evaluated as expression */
16
+ visible?: boolean | string | ((values: Record<string, unknown>) => boolean);
17
+ validators?: ValidatorFn[];
18
+ asyncValidators?: AsyncValidatorFn[];
19
+ mask?: string | MaskConfig;
20
+ /** For select / radio — static list, sync function, or async function */
21
+ options?: FieldOption[] | ((values: Record<string, unknown>) => FieldOption[] | Promise<FieldOption[]>);
22
+ /**
23
+ * Field names whose values trigger re-fetching of async options.
24
+ * Only relevant when `options` is an async function.
25
+ */
26
+ optionsDeps?: string[];
27
+ /** Internal: set by useForm when async options are loading. Read-only for consumers. */
28
+ optionsLoading?: boolean;
29
+ /** For group and array */
30
+ fields?: FieldDefinition[];
31
+ /**
32
+ * Applied on every setField call before the value is stored.
33
+ * Use for trimming, type coercion, formatting, etc.
34
+ */
35
+ transform?: (value: unknown, values: Record<string, unknown>) => unknown;
36
+ /**
37
+ * Applied at submit time to produce the final payload value.
38
+ * Runs after all validation passes.
39
+ */
40
+ parse?: (raw: unknown) => unknown;
41
+ /**
42
+ * Custom Vue component to render this field.
43
+ * Receives FormFieldProps and must emit 'update:modelValue' and 'blur'.
44
+ */
45
+ component?: Component | string;
46
+ }
47
+
48
+ declare interface FieldOption {
49
+ label: string;
50
+ value: unknown;
51
+ }
52
+
53
+ declare type FieldType = 'text' | 'number' | 'email' | 'select' | 'checkbox' | 'radio' | 'textarea' | 'date' | 'array' | 'group';
54
+
55
+ declare interface MaskConfig {
56
+ preset?: MaskPreset;
57
+ /** Custom mask pattern: '#' = digit, 'A' = letter, other chars are literals */
58
+ pattern?: string;
59
+ }
60
+
61
+ declare type MaskPreset = 'phone-ru' | 'phone-eu' | 'date' | 'inn' | 'iban';
62
+
63
+ /**
64
+ * Convert a Valibot `v.object(...)` schema into a `FieldDefinition[]`.
65
+ *
66
+ * Supported field types: string → text, number, boolean → checkbox,
67
+ * picklist/enum → select, array, object → group.
68
+ * `v.optional()` / `v.nullable()` wrappers set `required: false`.
69
+ * `v.pipe(v.string(), v.email())` sets `type: 'email'`.
70
+ *
71
+ * @example
72
+ * import * as v from 'valibot'
73
+ * import { parseValibot } from '@macrulez/vue-form-schema/valibot'
74
+ *
75
+ * const schema = v.object({ email: v.pipe(v.string(), v.email()), age: v.number() })
76
+ * const fields = parseValibot(schema)
77
+ */
78
+ export declare function parseValibot(schema: ValibotSchema): FieldDefinition[];
79
+
80
+ declare type ValibotSchema = any;
81
+
82
+ declare type ValidatorFn = (value: unknown, values: Record<string, unknown>) => string | null;
83
+
84
+ export { }
@@ -0,0 +1,43 @@
1
+ function u(t) {
2
+ if (!t || t.type !== "object" || !t.entries)
3
+ throw new Error("[vue-form-schema] parseValibot expects a v.object() schema");
4
+ return Object.entries(t.entries).map(
5
+ ([r, n]) => o(r, n)
6
+ );
7
+ }
8
+ function o(t, r) {
9
+ let n = !0, e = r;
10
+ (e.type === "optional" || e.type === "nullable" || e.type === "nullish") && (n = !1, e = e.wrapped ?? e);
11
+ const a = l(e), s = { type: a, name: t, required: n };
12
+ return a === "select" && (s.options = e.options.map((i) => ({
13
+ label: String(i),
14
+ value: i
15
+ }))), a === "group" && e.entries && (s.fields = Object.entries(e.entries).map(
16
+ ([i, p]) => o(i, p)
17
+ )), s;
18
+ }
19
+ function l(t) {
20
+ const r = t.type;
21
+ if (r === "string" && Array.isArray(t.pipe) && t.pipe.some((e) => e.type === "email"))
22
+ return "email";
23
+ switch (r) {
24
+ case "string":
25
+ return "text";
26
+ case "number":
27
+ return "number";
28
+ case "boolean":
29
+ return "checkbox";
30
+ case "picklist":
31
+ case "enum":
32
+ return "select";
33
+ case "array":
34
+ return "array";
35
+ case "object":
36
+ return "group";
37
+ default:
38
+ return "text";
39
+ }
40
+ }
41
+ export {
42
+ u as parseValibot
43
+ };
package/dist/yup.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { Component } from 'vue';
2
+
1
3
  declare type AsyncValidatorFn = (value: unknown, values: Record<string, unknown>) => Promise<string | null>;
2
4
 
3
5
  declare interface FieldDefinition {
@@ -15,10 +17,32 @@ declare interface FieldDefinition {
15
17
  validators?: ValidatorFn[];
16
18
  asyncValidators?: AsyncValidatorFn[];
17
19
  mask?: string | MaskConfig;
18
- /** For select / radio */
19
- options?: FieldOption[];
20
+ /** For select / radio — static list, sync function, or async function */
21
+ options?: FieldOption[] | ((values: Record<string, unknown>) => FieldOption[] | Promise<FieldOption[]>);
22
+ /**
23
+ * Field names whose values trigger re-fetching of async options.
24
+ * Only relevant when `options` is an async function.
25
+ */
26
+ optionsDeps?: string[];
27
+ /** Internal: set by useForm when async options are loading. Read-only for consumers. */
28
+ optionsLoading?: boolean;
20
29
  /** For group and array */
21
30
  fields?: FieldDefinition[];
31
+ /**
32
+ * Applied on every setField call before the value is stored.
33
+ * Use for trimming, type coercion, formatting, etc.
34
+ */
35
+ transform?: (value: unknown, values: Record<string, unknown>) => unknown;
36
+ /**
37
+ * Applied at submit time to produce the final payload value.
38
+ * Runs after all validation passes.
39
+ */
40
+ parse?: (raw: unknown) => unknown;
41
+ /**
42
+ * Custom Vue component to render this field.
43
+ * Receives FormFieldProps and must emit 'update:modelValue' and 'blur'.
44
+ */
45
+ component?: Component | string;
22
46
  }
23
47
 
24
48
  declare interface FieldOption {
package/dist/zod.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { Component } from 'vue';
2
+
1
3
  declare type AsyncValidatorFn = (value: unknown, values: Record<string, unknown>) => Promise<string | null>;
2
4
 
3
5
  declare interface FieldDefinition {
@@ -15,10 +17,32 @@ declare interface FieldDefinition {
15
17
  validators?: ValidatorFn[];
16
18
  asyncValidators?: AsyncValidatorFn[];
17
19
  mask?: string | MaskConfig;
18
- /** For select / radio */
19
- options?: FieldOption[];
20
+ /** For select / radio — static list, sync function, or async function */
21
+ options?: FieldOption[] | ((values: Record<string, unknown>) => FieldOption[] | Promise<FieldOption[]>);
22
+ /**
23
+ * Field names whose values trigger re-fetching of async options.
24
+ * Only relevant when `options` is an async function.
25
+ */
26
+ optionsDeps?: string[];
27
+ /** Internal: set by useForm when async options are loading. Read-only for consumers. */
28
+ optionsLoading?: boolean;
20
29
  /** For group and array */
21
30
  fields?: FieldDefinition[];
31
+ /**
32
+ * Applied on every setField call before the value is stored.
33
+ * Use for trimming, type coercion, formatting, etc.
34
+ */
35
+ transform?: (value: unknown, values: Record<string, unknown>) => unknown;
36
+ /**
37
+ * Applied at submit time to produce the final payload value.
38
+ * Runs after all validation passes.
39
+ */
40
+ parse?: (raw: unknown) => unknown;
41
+ /**
42
+ * Custom Vue component to render this field.
43
+ * Receives FormFieldProps and must emit 'update:modelValue' and 'blur'.
44
+ */
45
+ component?: Component | string;
22
46
  }
23
47
 
24
48
  declare interface FieldOption {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@macrulez/vue-form-schema",
3
- "version": "0.1.0",
4
- "description": "Reactive forms from JSON/Zod/Yup schema with validation, masking and conditional UI for Vue 3",
3
+ "version": "0.1.5",
4
+ "description": "Reactive forms from JSON/Zod/Yup/Valibot schema with validation, masking and conditional UI for Vue 3",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",
@@ -22,10 +22,20 @@
22
22
  "require": "./dist/yup.cjs",
23
23
  "types": "./dist/yup.d.ts"
24
24
  },
25
+ "./valibot": {
26
+ "import": "./dist/valibot.js",
27
+ "require": "./dist/valibot.cjs",
28
+ "types": "./dist/valibot.d.ts"
29
+ },
25
30
  "./ui": {
26
31
  "import": "./dist/ui.js",
27
32
  "require": "./dist/ui.cjs",
28
33
  "types": "./dist/ui.d.ts"
34
+ },
35
+ "./ui/tailwind": {
36
+ "import": "./dist/ui-tailwind.js",
37
+ "require": "./dist/ui-tailwind.cjs",
38
+ "types": "./dist/ui-tailwind.d.ts"
29
39
  }
30
40
  },
31
41
  "files": [
@@ -38,10 +48,28 @@
38
48
  "dev": "vite",
39
49
  "build": "vite build && tsc -p tsconfig.build.json",
40
50
  "demo": "vite --config vite.demo.config.ts",
41
- "test": "vitest",
42
- "test:coverage": "vitest --coverage",
51
+ "test": "vitest --config vitest.config.ts",
52
+ "test:coverage": "vitest --config vitest.config.ts --coverage",
43
53
  "typecheck": "tsc --noEmit"
44
54
  },
55
+ "keywords": [
56
+ "vue",
57
+ "vue3",
58
+ "form",
59
+ "schema",
60
+ "validation",
61
+ "zod",
62
+ "yup",
63
+ "composable",
64
+ "mask",
65
+ "reactive"
66
+ ],
67
+ "author": "macrulez",
68
+ "license": "MIT",
69
+ "bugs": {
70
+ "url": "https://github.com/macrulezru/vue-form-schema"
71
+ },
72
+ "homepage": "https://macrulez.ru/en",
45
73
  "peerDependencies": {
46
74
  "vue": "^3.3.0"
47
75
  },
@@ -51,14 +79,21 @@
51
79
  },
52
80
  "yup": {
53
81
  "optional": true
82
+ },
83
+ "valibot": {
84
+ "optional": true
54
85
  }
55
86
  },
56
87
  "devDependencies": {
57
88
  "@vitejs/plugin-vue": "^5.0.0",
58
89
  "@vitest/coverage-v8": "^1.0.0",
59
90
  "@vue/test-utils": "^2.4.0",
91
+ "autoprefixer": "^10.5.0",
60
92
  "happy-dom": "^20.9.0",
93
+ "postcss": "^8.5.15",
94
+ "tailwindcss": "^3.4.19",
61
95
  "typescript": "^5.3.0",
96
+ "valibot": "^1.4.0",
62
97
  "vite": "^5.0.0",
63
98
  "vite-plugin-dts": "^3.7.0",
64
99
  "vitest": "^1.0.0",
@@ -1,157 +0,0 @@
1
- const y = (t) => t == null || t === "" || Array.isArray(t) && t.length === 0 ? "This field is required" : null, M = (t, e) => (r) => typeof r != "string" && !Array.isArray(r) || r.length >= t ? null : e ?? `Minimum length is ${t}`, T = (t, e) => (r) => typeof r != "string" && !Array.isArray(r) || r.length <= t ? null : e ?? `Maximum length is ${t}`, v = (t, e) => (r) => {
2
- const s = Number(r);
3
- return isNaN(s) || s >= t ? null : e ?? `Minimum value is ${t}`;
4
- }, x = (t, e) => (r) => {
5
- const s = Number(r);
6
- return isNaN(s) || s <= t ? null : e ?? `Maximum value is ${t}`;
7
- }, I = (t, e) => (r) => typeof r != "string" || t.test(r) ? null : e ?? "Invalid format", b = (t) => t ? /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(t)) ? null : "Invalid email address" : null, E = (t) => {
8
- if (!t) return null;
9
- try {
10
- return new URL(String(t)), null;
11
- } catch {
12
- return "Invalid URL";
13
- }
14
- };
15
- class w {
16
- constructor(e = 300) {
17
- this.asyncTimers = /* @__PURE__ */ new Map(), this.debounceMs = e;
18
- }
19
- /** Run sync validators for a single field; returns list of error messages */
20
- validateField(e, r, s) {
21
- const i = [];
22
- if (e.required) {
23
- const n = y(r);
24
- n && i.push(n);
25
- }
26
- for (const n of e.validators ?? []) {
27
- const o = n(r, s);
28
- o && i.push(o);
29
- }
30
- return i;
31
- }
32
- /** Run all sync validators across all visible fields */
33
- validateAll(e, r) {
34
- const s = {};
35
- return this.collectErrors(e, r, s), s;
36
- }
37
- collectErrors(e, r, s) {
38
- for (const i of e) {
39
- const n = p(r, i.name), o = this.validateField(i, n, r);
40
- o.length && (s[i.name] = o), (i.type === "group" || i.type === "array") && i.fields && this.collectErrors(i.fields, r, s);
41
- }
42
- }
43
- /** Run async validators with debounce; calls onResult when done */
44
- validateAsync(e, r, s, i) {
45
- var l;
46
- if (!((l = e.asyncValidators) != null && l.length)) return;
47
- const n = this.asyncTimers.get(e.name);
48
- n && clearTimeout(n);
49
- const o = setTimeout(async () => {
50
- const c = (await Promise.all(
51
- e.asyncValidators.map((u) => u(r, s))
52
- )).filter((u) => u !== null);
53
- i(e.name, c), this.asyncTimers.delete(e.name);
54
- }, this.debounceMs);
55
- this.asyncTimers.set(e.name, o);
56
- }
57
- destroy() {
58
- for (const e of this.asyncTimers.values()) clearTimeout(e);
59
- this.asyncTimers.clear();
60
- }
61
- }
62
- function p(t, e) {
63
- return e.split(".").reduce((r, s) => {
64
- if (r && typeof r == "object") return r[s];
65
- }, t);
66
- }
67
- function P(t, e, r) {
68
- const s = e.split("."), i = { ...t };
69
- let n = i;
70
- for (let o = 0; o < s.length - 1; o++) {
71
- const l = s[o];
72
- n[l] = n[l] && typeof n[l] == "object" ? { ...n[l] } : {}, n = n[l];
73
- }
74
- return n[s[s.length - 1]] = r, i;
75
- }
76
- const A = {
77
- "phone-ru": "+7 (###) ###-##-##",
78
- "phone-eu": "+## (##) ###-##-##",
79
- date: "##.##.####",
80
- inn: "############",
81
- iban: "AA## #### #### #### #### #### ####"
82
- };
83
- function m(t) {
84
- return t.preset ? A[t.preset] : t.pattern ?? "";
85
- }
86
- function f(t) {
87
- return t === "#" || t === "A";
88
- }
89
- function h(t, e) {
90
- return e === "#" ? /\d/.test(t) : e === "A" ? /[a-zA-Z]/.test(t) : !1;
91
- }
92
- function d(t, e) {
93
- const s = m(typeof e == "string" ? { pattern: e } : e);
94
- if (!s) return t;
95
- const i = Array.from(t);
96
- let n = 0, o = -1;
97
- for (let a = 0; a < s.length && n < i.length; a++) {
98
- const c = s[a];
99
- if (f(c)) {
100
- for (; n < i.length && !h(i[n], c); ) n++;
101
- n < i.length && (o = a, n++);
102
- }
103
- }
104
- if (o === -1) return "";
105
- let l = "";
106
- n = 0;
107
- for (let a = 0; a <= o; a++) {
108
- const c = s[a];
109
- if (f(c)) {
110
- for (; n < i.length && !h(i[n], c); ) n++;
111
- n < i.length && (l += c === "A" ? i[n++].toUpperCase() : i[n++]);
112
- } else
113
- l += c;
114
- }
115
- return l;
116
- }
117
- function g(t, e) {
118
- const s = m(typeof e == "string" ? { pattern: e } : e);
119
- if (!s) return t;
120
- const i = [];
121
- let n = 0;
122
- for (let o = 0; o < s.length && n < t.length; o++) {
123
- const l = s[o], a = t[n];
124
- f(l) ? (i.push(a), n++) : a === l && n++;
125
- }
126
- return i.join("");
127
- }
128
- function S(t, e) {
129
- function r() {
130
- const i = g(t.value, e), n = d(i, e);
131
- if (t.value !== n) {
132
- const o = t.selectionStart ?? n.length;
133
- t.value = n;
134
- const l = Math.min(o, n.length);
135
- t.setSelectionRange(l, l);
136
- }
137
- }
138
- t.addEventListener("input", r);
139
- const s = d(g(t.value, e), e);
140
- return t.value !== s && s && (t.value = s), () => t.removeEventListener("input", r);
141
- }
142
- export {
143
- w as V,
144
- d as a,
145
- S as b,
146
- T as c,
147
- v as d,
148
- b as e,
149
- M as f,
150
- p as g,
151
- y as h,
152
- x as m,
153
- I as p,
154
- g as r,
155
- P as s,
156
- E as u
157
- };
@@ -1 +0,0 @@
1
- "use strict";const m=t=>t==null||t===""||Array.isArray(t)&&t.length===0?"This field is required":null,A=(t,e)=>r=>typeof r!="string"&&!Array.isArray(r)||r.length>=t?null:e??`Minimum length is ${t}`,M=(t,e)=>r=>typeof r!="string"&&!Array.isArray(r)||r.length<=t?null:e??`Maximum length is ${t}`,v=(t,e)=>r=>{const s=Number(r);return isNaN(s)||s>=t?null:e??`Minimum value is ${t}`},T=(t,e)=>r=>{const s=Number(r);return isNaN(s)||s<=t?null:e??`Maximum value is ${t}`},x=(t,e)=>r=>typeof r!="string"||t.test(r)?null:e??"Invalid format",E=t=>t?/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(t))?null:"Invalid email address":null,I=t=>{if(!t)return null;try{return new URL(String(t)),null}catch{return"Invalid URL"}};class b{constructor(e=300){this.asyncTimers=new Map,this.debounceMs=e}validateField(e,r,s){const i=[];if(e.required){const n=m(r);n&&i.push(n)}for(const n of e.validators??[]){const o=n(r,s);o&&i.push(o)}return i}validateAll(e,r){const s={};return this.collectErrors(e,r,s),s}collectErrors(e,r,s){for(const i of e){const n=y(r,i.name),o=this.validateField(i,n,r);o.length&&(s[i.name]=o),(i.type==="group"||i.type==="array")&&i.fields&&this.collectErrors(i.fields,r,s)}}validateAsync(e,r,s,i){var l;if(!((l=e.asyncValidators)!=null&&l.length))return;const n=this.asyncTimers.get(e.name);n&&clearTimeout(n);const o=setTimeout(async()=>{const c=(await Promise.all(e.asyncValidators.map(u=>u(r,s)))).filter(u=>u!==null);i(e.name,c),this.asyncTimers.delete(e.name)},this.debounceMs);this.asyncTimers.set(e.name,o)}destroy(){for(const e of this.asyncTimers.values())clearTimeout(e);this.asyncTimers.clear()}}function y(t,e){return e.split(".").reduce((r,s)=>{if(r&&typeof r=="object")return r[s]},t)}function P(t,e,r){const s=e.split("."),i={...t};let n=i;for(let o=0;o<s.length-1;o++){const l=s[o];n[l]=n[l]&&typeof n[l]=="object"?{...n[l]}:{},n=n[l]}return n[s[s.length-1]]=r,i}const w={"phone-ru":"+7 (###) ###-##-##","phone-eu":"+## (##) ###-##-##",date:"##.##.####",inn:"############",iban:"AA## #### #### #### #### #### ####"};function p(t){return t.preset?w[t.preset]:t.pattern??""}function f(t){return t==="#"||t==="A"}function g(t,e){return e==="#"?/\d/.test(t):e==="A"?/[a-zA-Z]/.test(t):!1}function h(t,e){const s=p(typeof e=="string"?{pattern:e}:e);if(!s)return t;const i=Array.from(t);let n=0,o=-1;for(let a=0;a<s.length&&n<i.length;a++){const c=s[a];if(f(c)){for(;n<i.length&&!g(i[n],c);)n++;n<i.length&&(o=a,n++)}}if(o===-1)return"";let l="";n=0;for(let a=0;a<=o;a++){const c=s[a];if(f(c)){for(;n<i.length&&!g(i[n],c);)n++;n<i.length&&(l+=c==="A"?i[n++].toUpperCase():i[n++])}else l+=c}return l}function d(t,e){const s=p(typeof e=="string"?{pattern:e}:e);if(!s)return t;const i=[];let n=0;for(let o=0;o<s.length&&n<t.length;o++){const l=s[o],a=t[n];f(l)?(i.push(a),n++):a===l&&n++}return i.join("")}function L(t,e){function r(){const i=d(t.value,e),n=h(i,e);if(t.value!==n){const o=t.selectionStart??n.length;t.value=n;const l=Math.min(o,n.length);t.setSelectionRange(l,l)}}t.addEventListener("input",r);const s=h(d(t.value,e),e);return t.value!==s&&s&&(t.value=s),()=>t.removeEventListener("input",r)}exports.ValidationEngine=b;exports.applyMask=h;exports.bindMask=L;exports.email=E;exports.getByPath=y;exports.max=T;exports.maxLength=M;exports.min=v;exports.minLength=A;exports.pattern=x;exports.removeMask=d;exports.required=m;exports.setByPath=P;exports.url=I;