kopular 0.12.0 → 0.13.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/LLM.md +14 -3
- package/README.md +15 -4
- package/package.json +1 -1
- package/src/forms.js +22 -0
- package/src/forms.js.map +1 -1
- package/src/forms.ks +34 -1
package/LLM.md
CHANGED
|
@@ -365,9 +365,20 @@ email.Valid(); // bool — Error.Value == null
|
|
|
365
365
|
**No array-of-validators parameter** — KopScript has no array-of-function-values type
|
|
366
366
|
(`((T) => string?)[]` doesn't parse: the parser reads a second `(...) => ...` immediately
|
|
367
367
|
after the first as a nested function type, not an array element type, and errors expecting
|
|
368
|
-
`=>`). Combine checks as an if-chain in one lambda
|
|
369
|
-
|
|
370
|
-
|
|
368
|
+
`=>`). Combine checks as an if-chain in one lambda (see the `email` example above), or via
|
|
369
|
+
the fixed-arity `CombineValidators2<T>`/`CombineValidators3<T>` free functions (generic,
|
|
370
|
+
inference-only — see `Kop`'s own "Generics" docs for why they're *free* functions, not
|
|
371
|
+
`Validators` static methods):
|
|
372
|
+
```ks
|
|
373
|
+
CombineValidators2((string v) => Validators.Required(v), (string v) => Validators.Email(v))
|
|
374
|
+
// -> a single (string) => string? — Required first, Email only if that passes
|
|
375
|
+
```
|
|
376
|
+
Fixed-arity (2, 3 — add more the same way if a form ever needs to chain further), not a
|
|
377
|
+
general `Validators.All(...)`, for the same array-of-function-values reason above.
|
|
378
|
+
|
|
379
|
+
**No DOM binding** — wiring `.Value` to a real `<input>` is a plain `addEventListener`
|
|
380
|
+
call in your own `Render()`, the same as any other event handler; there is no
|
|
381
|
+
`[(ngModel)]`-equivalent.
|
|
371
382
|
|
|
372
383
|
**No DOM binding** — wiring `.Value` to a real `<input>` is a plain `addEventListener`
|
|
373
384
|
call in your own `Render()`, the same as any other event handler; there is no
|
package/README.md
CHANGED
|
@@ -447,10 +447,21 @@ constructor exactly like `Counter`'s own `state<number>`, to re-render when they
|
|
|
447
447
|
A validator is a plain `(T) => string?` — `null` means valid, the same convention
|
|
448
448
|
KopScript's own nullable types use elsewhere. **There's no array-of-validators
|
|
449
449
|
constructor parameter** — KopScript has no syntax for an array of function values — so
|
|
450
|
-
combining more than one check (as `email` does above) is
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
450
|
+
combining more than one check (as `email` does above) is an `if`-chain in one lambda, or,
|
|
451
|
+
for the common case of just chaining a couple of already-built validators with no custom
|
|
452
|
+
logic of their own, the `CombineValidators2`/`CombineValidators3` free functions:
|
|
453
|
+
|
|
454
|
+
```ks
|
|
455
|
+
FormField<string> email = new FormField<string>("",
|
|
456
|
+
CombineValidators2((string v) => Validators.Required(v), (string v) => Validators.Email(v)));
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
Free functions, not `Validators` methods, and fixed-arity (2 and 3) rather than a general
|
|
460
|
+
`Validators.All(...)` — a class's own static method can't introduce a new type parameter
|
|
461
|
+
beyond the class's own (see "Generics" in `Kop`'s own docs), so a *generic* combinator has
|
|
462
|
+
to live as a free function instead. `Validators` ships the handful of checks almost every
|
|
463
|
+
form needs (`Required`, `MinLength`, `MaxLength`, `Email`, `Min`, `Max`), each returning
|
|
464
|
+
its own message; write your own validator function for anything more specific.
|
|
454
465
|
|
|
455
466
|
**No two-way data binding** — wiring `Value` to a real `<input>` is the
|
|
456
467
|
`addEventListener` call shown above, the same manual pattern `Counter` already uses for
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kopular",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Kopular: a small component framework for KopScript — components, reactive state, constructor-injected services, routing, real compiled templates, and HTTP, with no DI container",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/src/forms.js
CHANGED
|
@@ -13,6 +13,28 @@ class __KopState {
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
export function CombineValidators2(v1, v2) {
|
|
17
|
+
return (value) => {
|
|
18
|
+
let r1 = v1(value);
|
|
19
|
+
if ((r1 !== null)) {
|
|
20
|
+
return r1;
|
|
21
|
+
}
|
|
22
|
+
return v2(value);
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export function CombineValidators3(v1, v2, v3) {
|
|
26
|
+
return (value) => {
|
|
27
|
+
let r1 = v1(value);
|
|
28
|
+
if ((r1 !== null)) {
|
|
29
|
+
return r1;
|
|
30
|
+
}
|
|
31
|
+
let r2 = v2(value);
|
|
32
|
+
if ((r2 !== null)) {
|
|
33
|
+
return r2;
|
|
34
|
+
}
|
|
35
|
+
return v3(value);
|
|
36
|
+
};
|
|
37
|
+
}
|
|
16
38
|
export class FormField {
|
|
17
39
|
constructor(initial, validate) {
|
|
18
40
|
this.Value = new __KopState(initial);
|
package/src/forms.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forms.js","sources":["forms.ks"],"sourcesContent":["// FormField<T>: a single form input's value, validation state, and touched\n// flag, built on the same state<T> reactivity Component already uses — no\n// new reactive primitive, and deliberately no DOM binding of its own\n// (wiring Value to a real <input> is one addEventListener call in your own\n// Render(), the same as Counter's own click handler — see Kopular's README).\n//\n// A validator is a plain (T) => string? function: null means valid, the\n// same \"null means nothing to report\" convention KopScript's nullable\n// types already use elsewhere. There's no array of validators — KopScript\n// has no syntax for an array of function values — so combining more than\n// one check is
|
|
1
|
+
{"version":3,"file":"forms.js","sources":["forms.ks"],"sourcesContent":["// FormField<T>: a single form input's value, validation state, and touched\n// flag, built on the same state<T> reactivity Component already uses — no\n// new reactive primitive, and deliberately no DOM binding of its own\n// (wiring Value to a real <input> is one addEventListener call in your own\n// Render(), the same as Counter's own click handler — see Kopular's README).\n//\n// A validator is a plain (T) => string? function: null means valid, the\n// same \"null means nothing to report\" convention KopScript's nullable\n// types already use elsewhere. There's no array of validators — KopScript\n// has no syntax for an array of function values — so combining more than\n// one check is either an if-chain in one lambda, hand-written:\n//\n// FormField<string> name = new FormField<string>(\"\", (string v) => {\n// string? required = Validators.Required(v);\n// if (required != null) { return required; }\n// return Validators.MaxLength(v, 40);\n// });\n//\n// or the CombineValidators2/CombineValidators3 free functions below, for\n// the common case of just chaining a couple of already-built validators\n// with no custom logic of their own:\n//\n// FormField<string> name = new FormField<string>(\"\",\n// CombineValidators2((string v) => Validators.Required(v), (string v) => Validators.MaxLength(v, 40)));\n//\n// Free functions, not static Validators methods, and fixed-arity (2 and 3),\n// not a general array-taking Validators.All(...): KopScript has no\n// array-of-function-values type to accept a variable-length list with, and\n// a generic function can only be a *free* function in v1 — a class's own\n// static method can't introduce a new type parameter of its own beyond the\n// class's (Validators itself isn't generic) — see Kop's README/LLM.md\n// \"Generics\" section for exactly that cut. Add CombineValidators4 etc. the\n// same way if a real form ever needs to chain more than three.\n(T) => string? CombineValidators2<T>((T) => string? v1, (T) => string? v2) {\n return (T value) => {\n string? r1 = v1(value);\n if (r1 != null) { return r1; }\n return v2(value);\n };\n}\n\n(T) => string? CombineValidators3<T>((T) => string? v1, (T) => string? v2, (T) => string? v3) {\n return (T value) => {\n string? r1 = v1(value);\n if (r1 != null) { return r1; }\n string? r2 = v2(value);\n if (r2 != null) { return r2; }\n return v3(value);\n };\n}\nclass FormField<T> {\n public state<T> Value;\n public state<string?> Error;\n public state<bool> Touched;\n\n constructor(T initial, (T) => string? validate) {\n this.Value = state(initial);\n this.Error = state(validate(initial));\n this.Touched = state(false);\n this.Value.Subscribe((T v) => { this.Error.Value = validate(v); });\n }\n\n // Call on blur — separate from Error so a fresh, untouched field with an\n // invalid initial value (e.g. Required on an empty string) doesn't show\n // an error message before the user has had a chance to type anything.\n public void Touch() {\n this.Touched.Value = true;\n }\n\n public bool Valid() {\n return this.Error.Value == null;\n }\n}\n\n// A small set of common checks, each returning an error message or null —\n// not a validation framework, just the handful of checks almost every form\n// needs, so most fields don't have to hand-write string-length arithmetic.\nclass Validators {\n public static string? Required(string value) {\n if (value.Trim().Length == 0) { return \"Required\"; }\n return null;\n }\n\n public static string? MinLength(string value, number min) {\n if (value.Length < min) { return $\"Must be at least {min} characters\"; }\n return null;\n }\n\n public static string? MaxLength(string value, number max) {\n if (value.Length > max) { return $\"Must be at most {max} characters\"; }\n return null;\n }\n\n public static string? Email(string value) {\n return match value {\n r\"^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$\" => null,\n _ => \"Must be a valid email\"\n };\n }\n\n public static string? Min(number value, number min) {\n if (value < min) { return $\"Must be at least {min}\"; }\n return null;\n }\n\n public static string? Max(number value, number max) {\n if (value > max) { return $\"Must be at most {max}\"; }\n return null;\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AAiCA;EACE;EACE;EACA;IAAkB;;EAClB;;;AAIJ;EACE;EACE;EACA;IAAkB;;EAClB;EACA;IAAkB;;EAClB;;;AAGJ;EAKE;IACa;IACA;IACE;IACO;EAA6B;;;;EAM5C;IACc;;;EAGd;IACL;;;AAOJ;EACgB;IACZ;MAAgC;;IAChC;;;EAGY;IACZ;MAA0B;;IAC1B;;;EAGY;IACZ;MAA0B;;IAC1B;;;EAGY;IACZ;;EACE;;;EACA;;;;;;EAIU;IACZ;MAAmB;;IACnB;;;EAGY;IACZ;MAAmB;;IACnB"}
|
package/src/forms.ks
CHANGED
|
@@ -8,13 +8,46 @@
|
|
|
8
8
|
// same "null means nothing to report" convention KopScript's nullable
|
|
9
9
|
// types already use elsewhere. There's no array of validators — KopScript
|
|
10
10
|
// has no syntax for an array of function values — so combining more than
|
|
11
|
-
// one check is
|
|
11
|
+
// one check is either an if-chain in one lambda, hand-written:
|
|
12
12
|
//
|
|
13
13
|
// FormField<string> name = new FormField<string>("", (string v) => {
|
|
14
14
|
// string? required = Validators.Required(v);
|
|
15
15
|
// if (required != null) { return required; }
|
|
16
16
|
// return Validators.MaxLength(v, 40);
|
|
17
17
|
// });
|
|
18
|
+
//
|
|
19
|
+
// or the CombineValidators2/CombineValidators3 free functions below, for
|
|
20
|
+
// the common case of just chaining a couple of already-built validators
|
|
21
|
+
// with no custom logic of their own:
|
|
22
|
+
//
|
|
23
|
+
// FormField<string> name = new FormField<string>("",
|
|
24
|
+
// CombineValidators2((string v) => Validators.Required(v), (string v) => Validators.MaxLength(v, 40)));
|
|
25
|
+
//
|
|
26
|
+
// Free functions, not static Validators methods, and fixed-arity (2 and 3),
|
|
27
|
+
// not a general array-taking Validators.All(...): KopScript has no
|
|
28
|
+
// array-of-function-values type to accept a variable-length list with, and
|
|
29
|
+
// a generic function can only be a *free* function in v1 — a class's own
|
|
30
|
+
// static method can't introduce a new type parameter of its own beyond the
|
|
31
|
+
// class's (Validators itself isn't generic) — see Kop's README/LLM.md
|
|
32
|
+
// "Generics" section for exactly that cut. Add CombineValidators4 etc. the
|
|
33
|
+
// same way if a real form ever needs to chain more than three.
|
|
34
|
+
(T) => string? CombineValidators2<T>((T) => string? v1, (T) => string? v2) {
|
|
35
|
+
return (T value) => {
|
|
36
|
+
string? r1 = v1(value);
|
|
37
|
+
if (r1 != null) { return r1; }
|
|
38
|
+
return v2(value);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
(T) => string? CombineValidators3<T>((T) => string? v1, (T) => string? v2, (T) => string? v3) {
|
|
43
|
+
return (T value) => {
|
|
44
|
+
string? r1 = v1(value);
|
|
45
|
+
if (r1 != null) { return r1; }
|
|
46
|
+
string? r2 = v2(value);
|
|
47
|
+
if (r2 != null) { return r2; }
|
|
48
|
+
return v3(value);
|
|
49
|
+
};
|
|
50
|
+
}
|
|
18
51
|
class FormField<T> {
|
|
19
52
|
public state<T> Value;
|
|
20
53
|
public state<string?> Error;
|