kopular 1.1.1 → 1.1.3

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 (2) hide show
  1. package/GUIDE.md +43 -6
  2. package/package.json +1 -1
package/GUIDE.md CHANGED
@@ -27,8 +27,12 @@ both scripts). `ks check src/app.ks` type-checks without building, if you just w
27
27
  - No implicit `this` — every member reference is `this.Field`/`this.Method()`, always,
28
28
  including inside a lambda.
29
29
  - `if`/`else`/`while`/`for`/`foreach (Type x in xs)` — all statements, no ternary. Use
30
- `match` for a conditional value: `match x { 1 => "one", _ => "other" }` (the `_` arm is
31
- required unless every case is covered, e.g. an enum).
30
+ `match` for a conditional value: `match x { "a" => "one", _ => "other" }`. **The subject
31
+ must be `string` or an `enum` — never `bool`/`number`/anything else, and every pattern
32
+ must be a string literal (or, for an enum subject, an `Enum.Member` name) — not a number,
33
+ not `true`/`false`.** The `_` arm is required unless every case is covered (only possible
34
+ for an enum subject, by naming every member). For a `bool`, use `if`/`else` instead —
35
+ there's no equivalent shorthand.
32
36
  - Lambdas need explicit parameter types: `(number x) => x * 2`.
33
37
  - Nullable: `string? name` — a nullable field forces `if (x != null) { ... }` before use;
34
38
  narrowing is scoped to that `if` block, not reachability-based (an early
@@ -43,6 +47,18 @@ both scripts). `ks check src/app.ks` type-checks without building, if you just w
43
47
  `.Slice(a, b)/.Concat(ys)/.Join(sep)/.Reduce(fn, initial)`.
44
48
  - `x == null` / `x != null` also match `undefined` — a missed `Array.Find`, an absent
45
49
  optional field, etc. all read as `null`.
50
+ - **No `.Match()`/`.Test()`/`.Exec()` on `string` — there is no direct regex-execute method
51
+ at all.** A regex literal (`r"^[a-z]+$"`) only means something as a `match` *pattern*.
52
+ The idiomatic way to classify or extract by character class is `.Split("")` (splits into
53
+ a `string[]` of single characters) plus `match` per character:
54
+ ```ks
55
+ bool isLetter = match c { r"^[a-z]$" => true, _ => false };
56
+ ```
57
+ Build up runs (words, tokens, ...) by iterating those characters and appending to an
58
+ accumulator string, flushing it whenever a non-matching character (or the end) is
59
+ reached — this covers tokenizing/extracting by character class without ever needing a
60
+ hand-written JS shim. Reach for a real shim (below) only for something a `match` pattern
61
+ genuinely can't express, like capturing a submatch.
46
62
  - No object-literal syntax anywhere (`{ key: value }` doesn't exist as a value). A JS API
47
63
  that needs one (rare — `fetch`'s options, `addEventListener`'s options object) needs a
48
64
  small hand-written `.js` shim; Kopular's own `Http`/`FormField` cover the common cases so
@@ -68,10 +84,31 @@ need one: `this.SomeService.Count.Subscribe((v) => this.Update());` in the const
68
84
 
69
85
  **Template bindings**: `{{ expr }}` text, `[prop]="expr"` (real fields for
70
86
  `id`/`className`/`value`/`disabled`/`checked`; anything else is a plain attribute),
71
- `(click)`/`(input)`/`(blur)`/`(change)` events, `[(value)]="Field"` two-way binding
72
- (`Field` can be a bare name, `this.Field`, or a path like `Qty.Value` — not a method call),
73
- `*if="expr"`, `*for="Type v of expr"` (element type required, no inference), `*mount="expr"`
74
- (embeds a live child component, composes with `*for`).
87
+ `(click)`/`(input)`/`(blur)`/`(change)` events, `*if="expr"`, `*for="Type v of expr"`
88
+ (element type required, no inference), `*mount="expr"` (embeds a live child component,
89
+ composes with `*for`).
90
+
91
+ **Two-way binding, `[(value)]="Field"`** — `Field` can be a bare name, `this.Field`, or a
92
+ member path; it's assigned back directly (`Field = e.target.value`), so it must resolve
93
+ to something assignable, never a method call. **A `state<T>` field needs `.Value` on the
94
+ end** — `[(value)]="Qty.Value"`, not `[(value)]="Qty"` (a bare `state<T>` isn't itself a
95
+ `string`, so binding it directly is a type error):
96
+ ```ks
97
+ public state<string> Qty;
98
+ constructor() : base() { this.Qty = state("1"); }
99
+ ```
100
+ ```html
101
+ <input [(value)]="Qty.Value" />
102
+ ```
103
+
104
+ **Exactly one top-level element per template — no auto-wrapping, a hard compile error
105
+ otherwise.** Wrap multiple top-level pieces in one real container element:
106
+ ```html
107
+ <div>
108
+ <input id="text" [(value)]="Draft" />
109
+ <button (click)="Submit()">Go</button>
110
+ </div>
111
+ ```
75
112
 
76
113
  **Hand-written `Render()`** (needed when logic is too dynamic for a template, or a template
77
114
  would obscure more than it clarifies):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kopular",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
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",