@neocompose/cli 0.84.4 → 0.85.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/CHANGELOG.md +30 -0
- package/dist/neo-runtime.mjs +6258 -3205
- package/dist/test-worker.mjs +4150 -1573
- package/package.json +1 -1
- package/skills/neocompose-cli/SKILL.md +1 -1
- package/skills/neocompose-cli/references/cli-development.md +1 -1
- package/skills/neocompose-cli/references/neoscript.md +137 -6
- package/skills/neocompose-cli/references/values-identities-and-references.md +4 -0
package/package.json
CHANGED
|
@@ -129,7 +129,7 @@ wrappers.
|
|
|
129
129
|
The marker near the top of `SKILL.md` must exactly match the package version:
|
|
130
130
|
|
|
131
131
|
```html
|
|
132
|
-
<!-- reviewed-through-cli: 0.
|
|
132
|
+
<!-- reviewed-through-cli: 0.85.0 -->
|
|
133
133
|
```
|
|
134
134
|
|
|
135
135
|
The quoted version above is checked too, so this instruction cannot go stale
|
|
@@ -124,6 +124,26 @@ class members and `IReceiver` members. The same applies to guards that return,
|
|
|
124
124
|
throw, or break. Reassignment clears the proof, and paths that did not pass the
|
|
125
125
|
guard cannot use it.
|
|
126
126
|
|
|
127
|
+
A class can construct each interface only once. A class value known to implement
|
|
128
|
+
`IBox<int>` cannot pass an `is IBox<string>` check, including through inherited
|
|
129
|
+
interfaces. Open classes can still acquire an unrelated interface. Checks between
|
|
130
|
+
interface-only receivers retain their runtime behavior.
|
|
131
|
+
|
|
132
|
+
Guards preserve a generic receiver's `T` identity and its declared bound. A
|
|
133
|
+
declaration pattern also keeps the original receiver's members: after
|
|
134
|
+
`if (item is not IReceiver receiver) return;`, `item` still has its class or
|
|
135
|
+
generic type, while `receiver` exposes `IReceiver`.
|
|
136
|
+
|
|
137
|
+
A later class guard retains these capabilities. For example, after checking
|
|
138
|
+
`item is IReceiver` and then `item is Furnace`, the original `item` exposes both
|
|
139
|
+
`Furnace` and `IReceiver` members. A sealed class that cannot implement the
|
|
140
|
+
proven interface remains an impossible test.
|
|
141
|
+
|
|
142
|
+
Guards also narrow named global values and static member paths. Qualified and
|
|
143
|
+
unqualified static access share the same proof, including inherited statics.
|
|
144
|
+
Assignments clear affected proofs. A closure must establish its own guard
|
|
145
|
+
because the stored value can change before the closure runs.
|
|
146
|
+
|
|
127
147
|
Functions, natives and interface functions can declare their own type
|
|
128
148
|
parameters after the name, each with an optional constraint and default:
|
|
129
149
|
|
|
@@ -172,18 +192,19 @@ Each instance binds defaults that read `this` to itself; invalid lambda bodies
|
|
|
172
192
|
are reported at the declaration by status, editor validation, and preparation.
|
|
173
193
|
Static delegate fields use static class scope: they can read static members
|
|
174
194
|
without an instance owner, and cannot access `this` or instance members.
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
195
|
+
Field initializers can read their declaring class's static members without a
|
|
196
|
+
qualifier, including inherited statics and reads inside nested object defaults:
|
|
197
|
+
`public int First = Run();` and `public static int Copy = Number;`.
|
|
198
|
+
Eager initializers cannot read instance members or `this`; static defaults also
|
|
199
|
+
cannot capture class-header parameters. Defer instance reads inside a delegate
|
|
200
|
+
lambda. A delegate field default may also name a method group bare.
|
|
180
201
|
`Value = Read` or `this.Read` binds each new instance to its own `Read`, and a
|
|
181
202
|
static function may be named as `Read` or qualified as `Holder.Read`/`Other.Read`.
|
|
182
203
|
A qualified method group must name a static function. Method groups use the same
|
|
183
204
|
signature rule as in a body, and a mismatch is reported at the declaration.
|
|
184
205
|
A static field that names another static copies a value, as in
|
|
185
206
|
`public static int B = Holder.A;`. A class, List, Set, or Dictionary static
|
|
186
|
-
already owns its value, so call `Clone()` or use `Reference`. A static delegate cannot copy another Class's delegate field,
|
|
207
|
+
already owns its value, so call `Clone()` or use `Reference`. A static delegate cannot copy another Class's delegate field, including an inherited one,
|
|
187
208
|
because its closure compiles in its own Class; wrap it as `() => Other.Call()`.
|
|
188
209
|
Omitted constructor fields use their authored defaults, including optional fields.
|
|
189
210
|
Writable collection defaults belong to each instance; mutations persist on later
|
|
@@ -195,7 +216,13 @@ needed type descriptors; spec-only types remain in the test candidate.
|
|
|
195
216
|
Generic primary constructors also accept stored collection arguments, such as
|
|
196
217
|
`public static Box<List<int>> Value = new([1, 2]);`. Stored replay uses the closed
|
|
197
218
|
parameter type to preserve collection references.
|
|
219
|
+
Stored constructors validate every authored type argument, including names nested
|
|
220
|
+
inside collections and generic types. An expected field type cannot hide an unknown
|
|
221
|
+
type in `new Box<List<MissingType>>()`.
|
|
198
222
|
Typed locals also accept generic class types such as `Box<int> box = new(1);`.
|
|
223
|
+
Generic class arguments remain invariant through inheritance: `IntBox : Box<int>`
|
|
224
|
+
can be assigned to `Box<int>`, but not `Box<string>`. Arguments are substituted
|
|
225
|
+
through every intermediate base class, including nested generic arguments.
|
|
199
226
|
Explicit lambda parameter annotations accept the same type grammar as
|
|
200
227
|
declarations, including `decimal`, generic parameters, collections, arrays, and
|
|
201
228
|
nullable types.
|
|
@@ -266,6 +293,9 @@ conditions being false also narrow receivers in later `else if` conditions.
|
|
|
266
293
|
A nullable value coalesced with a non-null fallback produces a non-null result,
|
|
267
294
|
including in constructor arguments: `new Sprite(item.Sprite ?? SpriteInfo.Empty)`.
|
|
268
295
|
A nullable fallback keeps the result nullable when the left operand can be null.
|
|
296
|
+
When a reference result is expected, `first ?? fallback` selects the reference
|
|
297
|
+
itself. A present reference to a null target does not select the fallback.
|
|
298
|
+
In a scalar context, references still read their targets before coalescing.
|
|
269
299
|
|
|
270
300
|
Treat lookup-return values with the same nullable narrowing rules.
|
|
271
301
|
|
|
@@ -332,6 +362,12 @@ this.A = Reference(this.Count); // A now names Count
|
|
|
332
362
|
this.A += 1; // reads A's target, writes it back
|
|
333
363
|
```
|
|
334
364
|
|
|
365
|
+
Conditional assignments such as `this.A = choose ? first : second` rebind `A`
|
|
366
|
+
when both branches supply references. Scalar branches write through `A`; a mixed
|
|
367
|
+
reference and scalar choice reads the selected reference's target. Constructors
|
|
368
|
+
may initialize their own reference fields this way, but cannot write through
|
|
369
|
+
external targets.
|
|
370
|
+
|
|
335
371
|
A plain value never becomes a reference: passing `3` to a `Reference<int>`
|
|
336
372
|
parameter is an error. A handle reference never owns, so it can't hold a new
|
|
337
373
|
list or a query result.
|
|
@@ -377,6 +413,33 @@ enum, parameter, or local may shadow it. Qualified members use their owner's
|
|
|
377
413
|
namespace and may be named `Math`; access one as `this.Math` or
|
|
378
414
|
`SomeValue.Math` without colliding with the builtin qualifier.
|
|
379
415
|
|
|
416
|
+
## Vector math
|
|
417
|
+
|
|
418
|
+
`Vector2`, `Vector3`, `Vector2Int`, and `Vector3Int` support `+`, `-`, unary
|
|
419
|
+
`-`, multiplication by a scalar in either order, and division by a scalar.
|
|
420
|
+
Both vector operands must have the same type. Integer vectors accept only
|
|
421
|
+
integer scalars; float vectors accept int or float. Integer division truncates
|
|
422
|
+
toward zero. Division by zero throws. `==` and `!=` keep exact component equality.
|
|
423
|
+
|
|
424
|
+
```neo
|
|
425
|
+
Vector2 next = position + direction * speed;
|
|
426
|
+
float distance = Vector2.Distance(position, target);
|
|
427
|
+
Vector2 heading = (target - position).normalized;
|
|
428
|
+
Vector2 step = Vector2.MoveTowards(position, target, speed);
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
All vectors expose read-only `magnitude` and `sqrMagnitude`, static `Distance`,
|
|
432
|
+
`Min`, `Max`, and constants `zero`, `one`, `up`, `down`, `left`, and `right`.
|
|
433
|
+
Three-dimensional vectors also have `forward` and `back`. Float vectors add
|
|
434
|
+
`normalized`, `Dot`, `Lerp`, and `MoveTowards`; `Vector3` adds `Cross`.
|
|
435
|
+
Integer vectors have no implicit conversion to float vectors.
|
|
436
|
+
|
|
437
|
+
`Color.Lerp(a, b, t)` interpolates all four channels, including alpha.
|
|
438
|
+
Both vector and Color `Lerp` clamp t to [0, 1]. `normalized` returns zero when
|
|
439
|
+
the magnitude is at most 0.00001. A negative MoveTowards delta moves away.
|
|
440
|
+
Computed properties are read-only; arithmetic, math results, and constants
|
|
441
|
+
are fresh values. Component writes retain the ordinary vector aliasing rules.
|
|
442
|
+
|
|
380
443
|
## String builtins
|
|
381
444
|
|
|
382
445
|
Use `text.Replace(search, replacement)` to return a string with every
|
|
@@ -388,6 +451,36 @@ may be null. The receiver stays unchanged.
|
|
|
388
451
|
return "banana".Replace("a", "o"); // "bonono"
|
|
389
452
|
```
|
|
390
453
|
|
|
454
|
+
Strings also have `Length`, `Substring(startIndex[, length])`, `IndexOf`,
|
|
455
|
+
`LastIndexOf`, `Split(separator)`, `PadLeft`/`PadRight(totalWidth[,
|
|
456
|
+
paddingChar])`, `Trim`, `TrimStart`, and `TrimEnd`, plus the statics
|
|
457
|
+
`string.Join(separator, values)`, `string.IsNullOrEmpty`, and
|
|
458
|
+
`string.IsNullOrWhiteSpace`. Lengths and indices count UTF-16 code units, every
|
|
459
|
+
comparison is ordinal, and whitespace is C#'s `char.IsWhiteSpace` set. `Split`
|
|
460
|
+
keeps empty entries and returns a new list. `Join` takes a `List<string>` or
|
|
461
|
+
`Set<string>`; turn other entries into text first with
|
|
462
|
+
`values.Select(v => $"{v}")`. `s?.Length` is an error; use
|
|
463
|
+
`string.IsNullOrEmpty(s)` or narrow first.
|
|
464
|
+
|
|
465
|
+
```neo
|
|
466
|
+
List<string> parts = this.Text.Trim().Split(" ");
|
|
467
|
+
int quantity = int.TryParse(parts[1]) ?? 0;
|
|
468
|
+
return $"{slot.ToString("D3")} {price.ToString("N2")}";
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
`int.Parse`, `float.Parse`, and `decimal.Parse` accept ASCII digits with an
|
|
472
|
+
optional sign (plus a fraction for `float` and `decimal`, and an exponent for
|
|
473
|
+
`float`) after trimming ASCII whitespace, and throw on anything else or on a
|
|
474
|
+
value the type can't hold. `TryParse` returns `null` instead of throwing.
|
|
475
|
+
`decimal.Parse` never rounds: more than 28 significant or fractional digits is
|
|
476
|
+
an error.
|
|
477
|
+
|
|
478
|
+
Numbers format only with an explicit format: `D<n>` (int only, zero-padded),
|
|
479
|
+
`F<n>` (fixed point), or `N<n>` (fixed point with `,` grouping), where `n` is 0
|
|
480
|
+
to 28 and defaults to 2 (1 for `D`). `float` rounds half to even from its exact
|
|
481
|
+
value, `decimal` rounds half away from zero, and a result that is all zeros has
|
|
482
|
+
no `-` sign. For plain text, use interpolation: `$"{value}"`.
|
|
483
|
+
|
|
391
484
|
Integer inputs assigned to `float` round to float32. This also applies to
|
|
392
485
|
function arguments and returns, collection entries, and `List.Repeat` with a
|
|
393
486
|
float entry type. `Contains` and `IndexOf` on float collections also convert
|
|
@@ -430,6 +523,44 @@ return this.Beds
|
|
|
430
523
|
.Take(10);
|
|
431
524
|
```
|
|
432
525
|
|
|
526
|
+
`Sum`, `Average`, `Min`, and `Max` accept zero arguments or one selector.
|
|
527
|
+
Sum/Average require int, float, or decimal values; Min/Max also accept strings
|
|
528
|
+
and bools. Null values are skipped. Sum returns zero on empty input; the other
|
|
529
|
+
reductions return null for nullable input and throw for required input.
|
|
530
|
+
Average of ints returns float. Decimal calculations stay exact; decimal Average
|
|
531
|
+
rounds half-even within Neo's 28-digit envelope. Float Min stops at the first
|
|
532
|
+
NaN; Max prefers ordinary values to NaN.
|
|
533
|
+
|
|
534
|
+
`MinBy((item) => item.Score)` and `MaxBy(...)` return the first entry with the
|
|
535
|
+
winning key. They skip null keys unless every key is null, then keep the first
|
|
536
|
+
entry. Empty input throws unless the entry type is nullable.
|
|
537
|
+
|
|
538
|
+
List and Set support `Aggregate((acc, item) => ...)`,
|
|
539
|
+
`Aggregate(seed, (acc, item) => ...)`, `Distinct()`, and
|
|
540
|
+
`Zip(other, (left, right) => ...)`. Aggregate visits entries in order; an empty
|
|
541
|
+
unseeded fold throws. Distinct retains first occurrences using Contains equality
|
|
542
|
+
and returns a read-only List, including nullable entries. Zip stops at the
|
|
543
|
+
shorter input.
|
|
544
|
+
|
|
545
|
+
`GroupBy((item) => item.Category)` returns a read-only dictionary of read-only
|
|
546
|
+
lists. `ToDictionary((item) => item.Name)` optionally accepts a second value
|
|
547
|
+
selector. Keys must be non-null strings or enum values; duplicate dictionary
|
|
548
|
+
keys throw. Dictionary callbacks take `(key, value)`. `.Keys` and `.Values`
|
|
549
|
+
return read-only lists in dictionary traversal order (integer-looking string
|
|
550
|
+
keys precede other strings in numeric order).
|
|
551
|
+
|
|
552
|
+
Chain `ThenBy` or `ThenByDescending` after OrderBy to add stable secondary keys.
|
|
553
|
+
An inferred `var` retains this capability; ordinary List/Set annotations,
|
|
554
|
+
function boundaries, and non-ordering queries erase it. Every ordering call is
|
|
555
|
+
eager: it caches keys and sorts the snapshot, costing O(n log n * k) for k key
|
|
556
|
+
levels. Each selector runs once per entry per level. Mutating a snapshot through an explicitly writable local alias invalidates its cached keys; ThenBy then throws until a new OrderBy establishes an ordering.
|
|
557
|
+
|
|
558
|
+
Writable ordered lists support `items.Sort()` for scalar entries or
|
|
559
|
+
`items.Sort((left, right) => left.Score - right.Score)` for an int comparison.
|
|
560
|
+
Sort returns void, preserves entry identity, and is stable. It rejects mutation
|
|
561
|
+
of the target list through aliases while comparisons run; entry fields retain
|
|
562
|
+
their existing write permissions. A failed comparison leaves the order unchanged.
|
|
563
|
+
|
|
433
564
|
Use `items.IndexOf(value)` to return the zero-based index of the first equal
|
|
434
565
|
list entry, or `-1` when the value is absent. `IndexOf` is list-only and uses
|
|
435
566
|
the same equality as `Contains`.
|
|
@@ -239,6 +239,10 @@ Reference<NeoDialogue>(id: "capitol-dialogue-id")
|
|
|
239
239
|
- Both forms are legal in a member's declaration default, not only inside a
|
|
240
240
|
value graph. A key written there resolves after every pass has run, so it may
|
|
241
241
|
name a row the same push creates.
|
|
242
|
+
- List and dictionary declaration defaults can contain slot references, including
|
|
243
|
+
nested collections: `List<Reference<int>> Counts = [Reference(root.Save.Bits)]`.
|
|
244
|
+
Each instance owns its collection; entries continue to target the original
|
|
245
|
+
root or static slot, including slots supplied by declaration defaults.
|
|
242
246
|
- Keep genuine structural references ID-based when their collection has no
|
|
243
247
|
stable symbol, path, or key surface. Animation track and frame-override
|
|
244
248
|
targets are selectors, not structural references: encode a stable
|