@neocompose/cli 0.86.0 → 0.87.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.86.0",
3
+ "version": "0.87.0",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -9,7 +9,7 @@ description: >-
9
9
  `@neocompose/cli` or `node cli/bin/neo.mjs` in the neo-compose repository.
10
10
  ---
11
11
 
12
- <!-- reviewed-through-cli: 0.86.0 -->
12
+ <!-- reviewed-through-cli: 0.87.0 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -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.86.0 -->
132
+ <!-- reviewed-through-cli: 0.87.0 -->
133
133
  ```
134
134
 
135
135
  The quoted version above is checked too, so this instruction cannot go stale
@@ -8,6 +8,7 @@ constructors, and construction-time settlement.
8
8
  - Declaration rules
9
9
  - Annotations and settings
10
10
  - Member and relation rules
11
+ - Function overloads
11
12
  - Computed initializers and declared constructors
12
13
  - Required constructors and settlement
13
14
  - Inheritance construction
@@ -400,6 +401,11 @@ empty set.
400
401
  public NeoAction<int> OnDamaged = [PlayHitFlash, ApplyDamage];
401
402
  ```
402
403
 
404
+ A nested field initializer such as `Watcher = new() { OnTally = [Handle] }`
405
+ can target an inherited generic method on its enclosing instance. The listener
406
+ uses that owning instance, including when declaration defaults are materialized.
407
+ Explicit receiver targets keep their captured instance.
408
+
403
409
  An instance-bound listener reachable through a stable project root keeps its
404
410
  receiver path, for example `public NeoAction<int> OnDamaged =
405
411
  [root.Assets.OnDamage];`. Pull refuses a bound receiver that has no
@@ -430,6 +436,44 @@ For world layer links, instantiate a project-authored descendant of
430
436
  `targetLayer` relation. The relation is the complete binding; do not add
431
437
  value-level target metadata.
432
438
 
439
+ ### Function overloads
440
+
441
+ A class may declare several functions with one name when their parameter
442
+ types differ:
443
+
444
+ ```neo
445
+ class Inventory {
446
+ public int Add(Item item) { return 1; }
447
+ public int Add(Item item, int count) { return count; }
448
+ public int Add(List<Item> items) { return items.Count; }
449
+ }
450
+ ```
451
+
452
+ A class's overload set for a name holds every function of that name it
453
+ declares or inherits. A derived class adding `Add(Item item, int count)` next
454
+ to an inherited `Add(Item item)` overloads it. Static and instance functions,
455
+ NSFunctions and native functions, and generic and non-generic functions mix
456
+ freely.
457
+
458
+ Every two functions in a set need different parameter types after dropping
459
+ nullability, substituting base type arguments, and renaming function type
460
+ parameters by position. So `Add(Item)` and `Add(Item?)` collide, and so do
461
+ `F()` and `F<T>()`. A `Find<T = Item>(T value)` occupies `Find(Item)`.
462
+
463
+ At most one function per name and class may be dispatched: `abstract`,
464
+ `virtual`, `override`, or an interface implementation. Overrides target that
465
+ one function. Interfaces can't overload, so an interface declares each
466
+ function name once. When several class functions share an interface
467
+ function's name, the one whose parameters match implements it.
468
+
469
+ `Equals` and names a platform class or interface declares, such as
470
+ `OnTriggerEnter2D` and lifecycle hooks, can't be overloaded. A function still
471
+ can't share a name with a field, property, getter, or action.
472
+
473
+ Overloads generate C# overloads with the same name. A plain overload stores
474
+ under the key `Name#<memberId>`. A dispatched or lone function keeps the key
475
+ `Name`, so a project without overloads stores exactly what it did before.
476
+
433
477
  ## Computed initializers and declared constructors
434
478
 
435
479
  Inherited member initializers read parameters from the constructor that declared
@@ -711,3 +755,19 @@ A semicolon after `Main = ...` inside the initializer is invalid. Editor and CLI
711
755
  diagnostics highlight that separator in the authored file, including global,
712
756
  static member, and protected root initializers. Statement semicolons inside
713
757
  function or delegate bodies remain valid.
758
+
759
+ ## Stored tuples
760
+
761
+ Declare fixed positions with ordinary types and optional labels:
762
+
763
+ ```neo
764
+ public (int Count, bool Enabled) State = (3, true);
765
+ public (int, (string Label, int Count))? Detail = null;
766
+ ```
767
+
768
+ Each position has a derived member descriptor. Do not author descriptor IDs.
769
+ Changing a label preserves its position and identity. Changing arity or moving
770
+ stored positions requires migrating existing values. A required tuple without
771
+ a default must be supplied during construction; it has no automatic zero tuple.
772
+ Owned class and collection elements keep the ordinary single-owner rule. Use
773
+ an explicit reference or clone when another stored value already owns them.
@@ -7,7 +7,9 @@ runtime ownership, evaluation, and migrations.
7
7
 
8
8
  - Inline bodies and snippets
9
9
  - Nullability and ownership
10
+ - Tuples and destructuring
10
11
  - References
12
+ - Overloaded calls
11
13
  - Numeric builtins
12
14
  - Collection builtins
13
15
  - Conditional and logical operators
@@ -330,6 +332,30 @@ Save, Session, Setter, or otherwise writable. A constructor writes only its
330
332
  `this` instance. A writable structured-leaf field still inherits the receiver's
331
333
  effective storage restrictions.
332
334
 
335
+ ## Tuples and destructuring
336
+
337
+ A tuple has at least two ordered elements. Labels are optional and explicit;
338
+ `Item1`, `Item2`, and later positional aliases always work. Labels do not affect
339
+ type identity. Slots are immutable, so replace a whole tuple to change a value.
340
+ Referenced objects retain their normal permissions and identity.
341
+
342
+ ```neo
343
+ (int Row, int Col) position = (Row: 2, Col: 3);
344
+ var (row, col) = position;
345
+ (int first, (bool enabled, int _)) = (1, (true, 9));
346
+ var score = positions.Select(((r, c)) => r + c);
347
+ foreach (var (key, value) in weights) { Debug.Log(key); }
348
+ ```
349
+
350
+ `((r, c)) =>` accepts one tuple; `(r, c) =>` accepts two parameters. Recursive
351
+ patterns work in declarations, loop bindings, and tuple lambda parameters. `_`
352
+ discards a position. Assignment deconstruction is not supported.
353
+
354
+ Tuple equality compares corresponding values recursively. Decimal scale does
355
+ not affect equality. Classes, collections, and explicit references compare by
356
+ identity. `Contains`, `IndexOf`, `Remove`, and `ToSet` use the same rule.
357
+ Nullable tuples use `(int, int)?`; nullable elements use `(int?, int)`.
358
+
333
359
  ## References
334
360
 
335
361
  `Reference<T>` names one stored row. `T` can be any value type, including
@@ -383,6 +409,39 @@ The target row decides every write. Writing an asset-owned target errors, and a
383
409
  `OnChanged` listeners fire when it rebinds and when its target's value changes.
384
410
  Inside a generic body, `Reference<T>` takes the category of `T`'s binding.
385
411
 
412
+ ## Overloaded calls
413
+
414
+ A call to an overloaded function picks one overload at compile time from its
415
+ arguments. Candidates are every overload the receiver's type sees, across all
416
+ inheritance levels; a type qualifier takes static ones, an instance receiver
417
+ instance ones. An overload applies when the argument count fits its required
418
+ and default parameters and each argument converts to its parameter. Lambdas,
419
+ method groups, `null`, collection literals, and `.North` apply by shape.
420
+
421
+ Among applicable overloads, the one whose parameters are closer to the
422
+ argument types wins: an exact type beats a conversion, and `Bag` beats `Item`
423
+ when `Bag : Item`. On a tie, the overload filling no defaults wins, then the
424
+ non-generic one. Otherwise the call is ambiguous: `Scale(float)` and
425
+ `Scale(decimal)` can't take an `int`, so write `2.0` or `2m`. A generic
426
+ overload takes explicit type arguments, or infers them from the arguments the
427
+ way a lone generic call does, with defaults filling parameters nothing infers.
428
+ An overload whose type arguments can't be inferred isn't a candidate: beside
429
+ `F(int a, string b)`, `F<T>(T a, T b)` takes `F(1, 2)` but not `F(1, "a")`.
430
+
431
+ A method group picks the overload whose parameters match the target delegate
432
+ type exactly, in assignments, `+=`, `OnChanged`, `@listeners`, and delegate
433
+ arguments. `var f = Read` is an error when `Read` is overloaded; give `f` a
434
+ delegate type.
435
+
436
+ Pass the delegate type to mock or spy on an overloaded function:
437
+
438
+ ```neo
439
+ var quote = mock.function<NeoDelegate<int, Item, int>>(Pricing.Quote);
440
+ ```
441
+
442
+ Script evaluation selects an overload with a signature:
443
+ `neo script eval --function "Inventory.Add(Item, int)"`.
444
+
386
445
  ## Numeric types
387
446
 
388
447
  `int` stores whole numbers and division truncates toward zero. Ordinary integer
@@ -753,30 +812,48 @@ Property, relational, list, and positional patterns are unsupported. Pattern
753
812
  cases in statement switches remain unsupported. Install the matching Unity
754
813
  SDK before exporting the new switch-expression IR; older SDKs reject it.
755
814
 
756
- ## Try/catch
815
+ ## Structured errors and finally
757
816
 
758
- Catch the string-valued NeoScript runtime-error channel with ordered filters:
817
+ Throw a required string or any `NeoError` subclass. String throws create
818
+ `NeoError` values. Each error has a required read-only `Message`, including
819
+ an empty message. Derive ordinary classes from `NeoError` to carry typed data.
759
820
 
760
821
  ```neo
761
822
  try {
762
823
  return GetUnsafe();
763
824
  }
764
- catch (string message) when (message == "1") {
765
- return "Site moved";
766
- }
767
- catch (string message) {
825
+ catch (NeoArgumentError error) when (error.Message != "") {
826
+ Report(error.Message);
768
827
  throw;
769
828
  }
829
+ catch (NeoError error) {
830
+ return Fallback();
831
+ }
832
+ finally {
833
+ ReleaseResource();
834
+ }
770
835
  ```
771
836
 
772
- Require braces and at least one `catch (string name)`. The catch binding is
773
- read-only and scoped to its filter/body. Put at most one unfiltered catch last.
774
- A false or failing filter continues matching the original error. Bare
775
- `throw;` is valid only inside a catch and rethrows the original message.
776
-
777
- Do not use typed exception classes, parameterless catch, `finally`, `using`,
778
- patterns, or host-exception recovery. Completed writes before an error are not
779
- rolled back.
837
+ A try needs catches, a finally block, or both. Catch bindings are read-only.
838
+ Typed catches match subclasses, and `catch (string message)` matches every
839
+ ordinary error while binding its Message. An unfiltered base catch must follow
840
+ all catches it covers. Filters run before any intervening finally blocks,
841
+ including across calls. A false or failing filter continues the original search.
842
+ Bare `throw;` rethrows the original payload from a catch.
843
+
844
+ Finally runs on normal completion, return, break, continue, and ordinary errors.
845
+ The return value is evaluated before cleanup. An error escaping cleanup replaces
846
+ the pending error; an error caught inside cleanup does not. Return and loop
847
+ transfers cannot escape a finally block. A nested loop may break or continue.
848
+ Bare throw inside finally needs its own inner catch.
849
+
850
+ Runtime failures use `NeoNullReferenceError`, `NeoIndexOutOfRangeError`,
851
+ `NeoKeyNotFoundError`, `NeoArgumentError`, `NeoArithmeticError`, or
852
+ `NeoInvalidOperationError`. Unexpected native failures become `NeoHostError`
853
+ with Message `"Check logs for more details."`. Execution limits, unavailable
854
+ preview natives, cancellation, and invalid compiled data are noncatchable.
855
+ Suspended Unity calls retain cleanup until resumed; abandonment skips cleanup.
856
+ Completed writes are not rolled back. Install the matching SDK for schema 45.
780
857
 
781
858
  ## Debug output
782
859