@mosaicoo/form-core 0.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.
Files changed (38) hide show
  1. package/README.md +37 -0
  2. package/dist/index.d.ts +8 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +10 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/interop/importer.d.ts +38 -0
  7. package/dist/interop/importer.d.ts.map +1 -0
  8. package/dist/interop/importer.js +29 -0
  9. package/dist/interop/importer.js.map +1 -0
  10. package/dist/interop/legacy/legacy-exporter.d.ts +14 -0
  11. package/dist/interop/legacy/legacy-exporter.d.ts.map +1 -0
  12. package/dist/interop/legacy/legacy-exporter.js +234 -0
  13. package/dist/interop/legacy/legacy-exporter.js.map +1 -0
  14. package/dist/interop/legacy/legacy-importer.d.ts +25 -0
  15. package/dist/interop/legacy/legacy-importer.d.ts.map +1 -0
  16. package/dist/interop/legacy/legacy-importer.js +382 -0
  17. package/dist/interop/legacy/legacy-importer.js.map +1 -0
  18. package/dist/schema/types.d.ts +181 -0
  19. package/dist/schema/types.d.ts.map +1 -0
  20. package/dist/schema/types.js +9 -0
  21. package/dist/schema/types.js.map +1 -0
  22. package/dist/schema/walk.d.ts +27 -0
  23. package/dist/schema/walk.d.ts.map +1 -0
  24. package/dist/schema/walk.js +56 -0
  25. package/dist/schema/walk.js.map +1 -0
  26. package/dist/state/engine.d.ts +93 -0
  27. package/dist/state/engine.d.ts.map +1 -0
  28. package/dist/state/engine.js +358 -0
  29. package/dist/state/engine.js.map +1 -0
  30. package/dist/util/clone.d.ts +6 -0
  31. package/dist/util/clone.d.ts.map +1 -0
  32. package/dist/util/clone.js +18 -0
  33. package/dist/util/clone.js.map +1 -0
  34. package/dist/validation/validate.d.ts +35 -0
  35. package/dist/validation/validate.d.ts.map +1 -0
  36. package/dist/validation/validate.js +113 -0
  37. package/dist/validation/validate.js.map +1 -0
  38. package/package.json +47 -0
@@ -0,0 +1,113 @@
1
+ const DEFAULT_MESSAGES = {
2
+ required: '{{label}} is required',
3
+ minLength: '{{label}} must have at least {{value}} characters',
4
+ maxLength: '{{label}} must have at most {{value}} characters',
5
+ pattern: '{{label}} does not match the expected format',
6
+ min: '{{label}} must be {{value}} or more',
7
+ max: '{{label}} must be {{value}} or less',
8
+ email: '{{label}} must be a valid email address',
9
+ custom: '{{label}} is invalid',
10
+ };
11
+ export const defaultMessageResolver = (rule, field, spec) => {
12
+ const explicit = spec && 'message' in spec ? spec.message : undefined;
13
+ const template = explicit ?? DEFAULT_MESSAGES[rule.split(':')[0] ?? ''] ?? '{{label}} is invalid';
14
+ const value = spec && 'value' in spec ? String(spec.value) : '';
15
+ return template
16
+ .replace(/\{\{\s*label\s*\}\}/g, field.label ?? field.key)
17
+ .replace(/\{\{\s*value\s*\}\}/g, value);
18
+ };
19
+ const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
20
+ export function isEmptyValue(value) {
21
+ if (value === undefined || value === null)
22
+ return true;
23
+ if (typeof value === 'string')
24
+ return value.trim() === '';
25
+ if (Array.isArray(value))
26
+ return value.length === 0;
27
+ if (typeof value === 'object') {
28
+ // A choice-map value ({ red: true, blue: false }) is empty when nothing
29
+ // is selected; an all-null object (e.g. untouched composite) is empty.
30
+ const values = Object.values(value);
31
+ return values.every((v) => v === false || v === null || v === undefined || v === '');
32
+ }
33
+ return false;
34
+ }
35
+ /**
36
+ * Validates a single input field value against its declared validators.
37
+ * Empty values only fail `required` — the remaining rules apply to provided
38
+ * values, so optional fields stay optional.
39
+ */
40
+ export function validateFieldValue(field, path, value, data, options) {
41
+ const specs = field.validators ?? [];
42
+ const resolve = options?.messages ?? defaultMessageResolver;
43
+ const errors = [];
44
+ const empty = isEmptyValue(value);
45
+ for (const spec of specs) {
46
+ if (spec.type === 'required') {
47
+ if (empty)
48
+ errors.push({ path, rule: 'required', message: resolve('required', field, spec) });
49
+ continue;
50
+ }
51
+ if (empty)
52
+ continue;
53
+ switch (spec.type) {
54
+ case 'minLength':
55
+ if (typeof value === 'string' && value.length < spec.value) {
56
+ errors.push({ path, rule: 'minLength', message: resolve('minLength', field, spec) });
57
+ }
58
+ break;
59
+ case 'maxLength':
60
+ if (typeof value === 'string' && value.length > spec.value) {
61
+ errors.push({ path, rule: 'maxLength', message: resolve('maxLength', field, spec) });
62
+ }
63
+ break;
64
+ case 'pattern': {
65
+ const re = safeRegExp(spec.value);
66
+ if (re && typeof value === 'string' && !re.test(value)) {
67
+ errors.push({ path, rule: 'pattern', message: resolve('pattern', field, spec) });
68
+ }
69
+ break;
70
+ }
71
+ case 'min':
72
+ if (typeof value === 'number' && value < spec.value) {
73
+ errors.push({ path, rule: 'min', message: resolve('min', field, spec) });
74
+ }
75
+ break;
76
+ case 'max':
77
+ if (typeof value === 'number' && value > spec.value) {
78
+ errors.push({ path, rule: 'max', message: resolve('max', field, spec) });
79
+ }
80
+ break;
81
+ case 'email':
82
+ if (typeof value === 'string' && !EMAIL_RE.test(value)) {
83
+ errors.push({ path, rule: 'email', message: resolve('email', field, spec) });
84
+ }
85
+ break;
86
+ case 'custom': {
87
+ const fn = options?.registry?.[spec.name];
88
+ if (!fn)
89
+ break; // unknown custom validators never block the user
90
+ const result = fn(value, spec.args ?? {}, { field, path, data });
91
+ if (result !== true) {
92
+ const message = typeof result === 'string' ? result : resolve(`custom:${spec.name}`, field, spec);
93
+ errors.push({ path, rule: `custom:${spec.name}`, message });
94
+ }
95
+ break;
96
+ }
97
+ }
98
+ }
99
+ return errors;
100
+ }
101
+ const regexpCache = new Map();
102
+ function safeRegExp(source) {
103
+ if (!regexpCache.has(source)) {
104
+ try {
105
+ regexpCache.set(source, new RegExp(source));
106
+ }
107
+ catch {
108
+ regexpCache.set(source, null); // invalid pattern in schema — never throw at runtime
109
+ }
110
+ }
111
+ return regexpCache.get(source) ?? null;
112
+ }
113
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/validation/validate.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@mosaicoo/form-core",
3
+ "version": "0.1.0",
4
+ "description": "Headless form engine: schema model, state, validation, conditional logic and pluggable importers",
5
+ "license": "MIT",
6
+ "author": "Mosaicoo",
7
+ "homepage": "https://github.com/mosaicoo/mosaicoo-form#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/mosaicoo/mosaicoo-form.git",
11
+ "directory": "packages/core"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/mosaicoo/mosaicoo-form/issues"
15
+ },
16
+ "keywords": [
17
+ "forms",
18
+ "form-engine",
19
+ "headless",
20
+ "dynamic-forms",
21
+ "validation",
22
+ "schema",
23
+ "typescript"
24
+ ],
25
+ "type": "module",
26
+ "main": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "default": "./dist/index.js"
32
+ }
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "README.md"
37
+ ],
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "scripts": {
42
+ "build": "tsc -p tsconfig.json",
43
+ "test": "vitest run",
44
+ "test:watch": "vitest"
45
+ },
46
+ "sideEffects": false
47
+ }