@neocompose/cli 0.75.1 → 0.76.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 +42 -0
- package/dist/neo.mjs +8525 -8883
- package/dist/test-worker.mjs +1242 -1006
- package/package.json +1 -1
- package/skills/neocompose-cli/SKILL.md +9 -4
- package/skills/neocompose-cli/references/animation-and-world-authoring.md +3 -2
- package/skills/neocompose-cli/references/cli-development.md +5 -2
- package/skills/neocompose-cli/references/declarations-and-construction.md +60 -3
- package/skills/neocompose-cli/references/neoscript.md +4 -3
- package/skills/neocompose-cli/references/values-identities-and-references.md +39 -0
package/package.json
CHANGED
|
@@ -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.
|
|
12
|
+
<!-- reviewed-through-cli: 0.76.0 -->
|
|
13
13
|
|
|
14
14
|
# Neo Compose CLI
|
|
15
15
|
|
|
@@ -211,8 +211,12 @@ copies, use the editor's duplicate action or copy the initializer without IDs.
|
|
|
211
211
|
Scalars may have several owners. If those values diverge in web, pull keeps
|
|
212
212
|
the different server values by inlining the differing uses. Initializer
|
|
213
213
|
aliases are local source organization, not runtime globals or server records.
|
|
214
|
-
|
|
215
|
-
|
|
214
|
+
Complete member and collection entries compose owned values, including inside
|
|
215
|
+
constructor-backed initializers. A class local used as a constructor argument or
|
|
216
|
+
executable operand refers to its single stored instance. Nested targets need an
|
|
217
|
+
existing `@id` or an authored UUID-v4; a direct static owner supports pending IDs.
|
|
218
|
+
Scalar executable expressions such as `BASE + 1` still require inlining the
|
|
219
|
+
scalar expression. Locals are unavailable inside executable closures.
|
|
216
220
|
The shared editor offers extract-to-file on a selected complete initializer,
|
|
217
221
|
inline on its sole use, and duplicate at a use. Move the created file freely.
|
|
218
222
|
|
|
@@ -308,5 +312,6 @@ and `insert_final_newline` there to keep regenerated source consistent with your
|
|
|
308
312
|
editor. Defaults are two spaces, LF, and a final newline. Push preserves authored
|
|
309
313
|
text when regeneration has the same tokens; pull preserves semantically unchanged
|
|
310
314
|
files. Formatting-only body or source-location changes do not create a subsequent
|
|
311
|
-
push
|
|
315
|
+
push, including stored initializer recipes, computed member defaults, and inline
|
|
316
|
+
constructor delegates; real code and string-content edits still do. Formatting preferences belong
|
|
312
317
|
to the checkout, not stored script bodies.
|
|
@@ -66,8 +66,9 @@ new GlassFloorTile { Cell = new(9, -4) }
|
|
|
66
66
|
|
|
67
67
|
Layer-link `Tiles` lists contain these values directly. `NeoTileInstance` and
|
|
68
68
|
`@tile(...)` are removed. A tile's `Name`, `Sprite`, and `SmartTile` are
|
|
69
|
-
`readonly`
|
|
70
|
-
|
|
69
|
+
class-level `readonly` members: tiles render per class, so override them on a
|
|
70
|
+
subclass. Push rejects a placement that sets them. `Cell` is the placement's
|
|
71
|
+
writable field.
|
|
71
72
|
|
|
72
73
|
Object `PlacementTiles` is a `List<NeoPlacementTile>`. Each entry marks a
|
|
73
74
|
footprint cell with its own `Cell` member. It is independent of `NeoTile`. Rendered
|
|
@@ -105,7 +105,10 @@ project-file bytes, and web editor commits use the shared client preparation pro
|
|
|
105
105
|
Unrelated source files are not uploaded or recompiled on every push.
|
|
106
106
|
Optional source maps missing from valid stored bodies do not request a backfill.
|
|
107
107
|
Formatting-only source location changes do not create pushes, including when
|
|
108
|
-
other records change.
|
|
108
|
+
other records change. Stored initializer recipes, computed member defaults, and
|
|
109
|
+
inline constructor delegates preserve their pulled code and compiled bodies when
|
|
110
|
+
source tokens are unchanged. String-literal content remains significant.
|
|
111
|
+
Evaluation maps the current local layout; authored edits,
|
|
109
112
|
dependency changes, and explicit forced recompilation retain their normal compile scope. A CLI lowering mismatch on a normal push is exposed by the next
|
|
110
113
|
canonical pull; `neo push --dry-run` remains the complete source-to-record
|
|
111
114
|
rehearsal.
|
|
@@ -126,7 +129,7 @@ wrappers.
|
|
|
126
129
|
The marker near the top of `SKILL.md` must exactly match the package version:
|
|
127
130
|
|
|
128
131
|
```html
|
|
129
|
-
<!-- reviewed-through-cli: 0.
|
|
132
|
+
<!-- reviewed-through-cli: 0.76.0 -->
|
|
130
133
|
```
|
|
131
134
|
|
|
132
135
|
The quoted version above is checked too, so this instruction cannot go stale
|
|
@@ -166,6 +166,24 @@ a User class reads only `root.User`. Other code reads `root.User` but can't
|
|
|
166
166
|
assign, mutate, construct, or invoke User data. Lookups and listeners don't
|
|
167
167
|
cross between User and Save data; Session lookups may target `root.User`.
|
|
168
168
|
|
|
169
|
+
`readonly` is init-only, as in C#, and independent of storage. A field
|
|
170
|
+
initializer, a constructor body, an object initializer block, or an authored
|
|
171
|
+
value sets it; nothing writes it after construction. It is valid on Save,
|
|
172
|
+
Session, Immutable, and User classes, but not with Writable storage. It may
|
|
173
|
+
read a header parameter:
|
|
174
|
+
|
|
175
|
+
```neo
|
|
176
|
+
class MixerGroup(string name) {
|
|
177
|
+
public readonly string Name = name;
|
|
178
|
+
public readonly List<MixerChannel> Children = [];
|
|
179
|
+
public float Volume = 1;
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Readonly is shallow. A readonly collection's membership is fixed, while its
|
|
184
|
+
entries' members follow their own storage and mutability. User class members
|
|
185
|
+
still declare no storage.
|
|
186
|
+
|
|
169
187
|
`@index(member: Field, kind: .Unique)` and
|
|
170
188
|
`@column(member: Field, width: ..., visibility: ..., pin: ..., overflow: ...)`
|
|
171
189
|
are repeatable List annotations. `member:` is a bare field name on the entry
|
|
@@ -369,8 +387,8 @@ Accept settlement only from:
|
|
|
369
387
|
|
|
370
388
|
1. The member's own initializer expression.
|
|
371
389
|
2. Assignment on every reachable path in `init` or a constructor body.
|
|
372
|
-
3. A call-site initializer entry
|
|
373
|
-
path.
|
|
390
|
+
3. A call-site initializer entry, in value source and NeoScript bodies alike,
|
|
391
|
+
when using an otherwise valid construction path.
|
|
374
392
|
|
|
375
393
|
Do not infer settlement from a side effect inside another function. Require
|
|
376
394
|
full `if`/`else` coverage when an assignment is conditional.
|
|
@@ -434,7 +452,21 @@ class PlacedItem<
|
|
|
434
452
|
}
|
|
435
453
|
```
|
|
436
454
|
|
|
437
|
-
|
|
455
|
+
Object initializer blocks can set `readonly` members of the newly constructed
|
|
456
|
+
instance, including nested `new` expressions. Ordinary assignments after
|
|
457
|
+
construction remain subject to storage and `readonly` restrictions.
|
|
458
|
+
|
|
459
|
+
Runtime construction never supplies an Immutable member: an initializer block,
|
|
460
|
+
constructor body, base-clause argument, or generated C# factory cannot set one.
|
|
461
|
+
The value is never stored with the instance. When the declaration, including
|
|
462
|
+
every row it owns, reads neither `this` nor a constructor argument, the member
|
|
463
|
+
is a constant and every instance shares one value. Otherwise each instance
|
|
464
|
+
evaluates the declared initializer with its own `this` and constructor
|
|
465
|
+
arguments, again after a reload. A method group such as `selector: SelectTorso`
|
|
466
|
+
binds `this`. `Clone()` shares an authored or constant Immutable value and
|
|
467
|
+
re-evaluates a per-instance one. A class with a required Immutable member and
|
|
468
|
+
no initializer cannot be constructed at runtime; only authored values construct
|
|
469
|
+
it.
|
|
438
470
|
|
|
439
471
|
Populated unordered member defaults, such as `@settings(kind: .Unordered)` with
|
|
440
472
|
`List<Entry> Entries = [new Entry()]`, are constructed by an initializer for
|
|
@@ -446,3 +478,28 @@ A lookup's declared class must be assignable to the entry class of its
|
|
|
446
478
|
selection. Constructor arguments and member initializers must select compatible
|
|
447
479
|
targets too. An `NPC` lookup cannot select from `List<Quest>`, even when its
|
|
448
480
|
initializer is typed `NPC`; status reports the conflicting collection annotation.
|
|
481
|
+
|
|
482
|
+
Schema export retains a constructed default's generic arguments, including
|
|
483
|
+
nested collection references. For example, a `NeoAnimationClip<ArmPart>`
|
|
484
|
+
default constructs `new NeoAnimationClip<ArmPart>` and its frames reference
|
|
485
|
+
`List<NeoAnimationFrame<ArmPart>>`.
|
|
486
|
+
|
|
487
|
+
When a construction leaves a required member unsettled, CLI diagnostics point to
|
|
488
|
+
`new` and include the member declaration as a related location. Fix that
|
|
489
|
+
construction before pushing. Valid root initializers still participate in
|
|
490
|
+
reference checking, so an unrelated root error does not imply their values are
|
|
491
|
+
missing or deleted. Independent reference errors remain visible.
|
|
492
|
+
|
|
493
|
+
Object initializer assignments use commas. The last comma is optional; the
|
|
494
|
+
semicolon terminating the enclosing declaration is valid:
|
|
495
|
+
|
|
496
|
+
```neo
|
|
497
|
+
AudioSettings AUDIO_SETTINGS = new() {
|
|
498
|
+
Main = new AudioMixerGroupSettingsFolder("Main", "Master", "MasterVolume", []),
|
|
499
|
+
};
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
A semicolon after `Main = ...` inside the initializer is invalid. Editor and CLI
|
|
503
|
+
diagnostics highlight that separator in the authored file, including global,
|
|
504
|
+
static member, and protected root initializers. Statement semicolons inside
|
|
505
|
+
function or delegate bodies remain valid.
|
|
@@ -154,9 +154,10 @@ Object initializers are available in method bodies and `.spec.neo` tests:
|
|
|
154
154
|
var tile = new DirtWetTile { Cell = Vector2Int(3, -2) };
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
157
|
+
An entry that settles a required member is evaluated with construction, as the
|
|
158
|
+
constructor argument it stands in for. The remaining entries then use ordinary
|
|
159
|
+
assignment rules in source order, including property setters, access checks,
|
|
160
|
+
and readonly restrictions. Initializer expressions read the caller's scope.
|
|
160
161
|
|
|
161
162
|
## Nullability and ownership
|
|
162
163
|
|
|
@@ -90,6 +90,45 @@ formatting moves its ID above the declaration. Do not put an ID in both places.
|
|
|
90
90
|
A local initializer such as `Delivery DeliveryRow = new()` retains `Delivery`
|
|
91
91
|
when consumed by a base-class member. Aliases retain that same concrete type.
|
|
92
92
|
|
|
93
|
+
Complete local member and collection initializers also work inside constructions
|
|
94
|
+
that execute a constructor. Each local composes its owned subtree and preserves
|
|
95
|
+
its concrete class:
|
|
96
|
+
|
|
97
|
+
```neo
|
|
98
|
+
AudioFolder SFX_FOLDER = new("Sound effects") {
|
|
99
|
+
Children = [UI_VOLUME, GAMEPLAY_VOLUME]
|
|
100
|
+
};
|
|
101
|
+
AudioSettings AUDIO_SETTINGS = new() { Main = SFX_FOLDER };
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
In constructor arguments and executable operands, a class local names its one
|
|
105
|
+
stored instance instead of constructing a copy:
|
|
106
|
+
|
|
107
|
+
```neo
|
|
108
|
+
@id("86ac7c7d-8d3b-4642-9def-cdf32643bdc5")
|
|
109
|
+
DeliveryQuest HARD_AS_STONE = new();
|
|
110
|
+
// The core quest list owns HARD_AS_STONE.
|
|
111
|
+
WorkflowStep UNLOCK = new QuestUnlockStep(HARD_AS_STONE);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The referenced local must have exactly one owning placement. A nested target
|
|
115
|
+
needs its existing `@id`. A structurally owned list entry can also use an unused
|
|
116
|
+
UUID-v4 in the same push. For a local nested inside an evaluated constructor,
|
|
117
|
+
leave it idless on the first push; push assigns its actual identity before it can
|
|
118
|
+
be referenced. Do not assign a fresh UUID to that nested construction. A direct static owning member can supply an idless local's pending identity.
|
|
119
|
+
Aliases of that static local work too. A member default is a construction template,
|
|
120
|
+
so its local does not identify a single stored instance. Unowned locals, ambiguous
|
|
121
|
+
placements, and cycles are errors at source. Constructor argument type checking
|
|
122
|
+
still applies. Canonical construction arguments may use `Reference<Type>(id: "…")`.
|
|
123
|
+
|
|
124
|
+
Owned locals inside evaluated initializers need directly addressable fields, list
|
|
125
|
+
entries, or literal dictionary keys; inline the construction when a computed key
|
|
126
|
+
or other executable expression prevents tracking its owning path.
|
|
127
|
+
|
|
128
|
+
Scalar locals remain complete-initializer bindings; inline their expressions when
|
|
129
|
+
using them in arithmetic or constructor arguments. Closure bodies cannot capture
|
|
130
|
+
project authoring locals.
|
|
131
|
+
|
|
93
132
|
Nested class/list rows remain independently addressable and keep inline IDs:
|
|
94
133
|
|
|
95
134
|
```neo
|