@neocompose/cli 0.30.3 → 0.31.1

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.30.3",
3
+ "version": "0.31.1",
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.30.3 -->
12
+ <!-- reviewed-through-cli: 0.31.1 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -109,6 +109,7 @@ neo/
109
109
  LocalizationStatuses/
110
110
  Files/{Images.neo,AudioClips.neo,Images/,AudioClips/}
111
111
  DialogueGroups/
112
+ Variants/{<Class>.neo,<Class>/<Folder path>.neo}
112
113
  Dialogues/*.neoflow
113
114
  Migrations/*.neo
114
115
  **/*.spec.neo
@@ -133,8 +134,9 @@ completely before editing:
133
134
  root/static bindings, nested/list identities, same-push references, unique
134
135
  keys, files, localization, and default materialization.
135
136
  - [Animation and world authoring](references/animation-and-world-authoring.md):
136
- objects, sorting, optional children, structured leaves, partial animation
137
- overrides, segments, tracks, and NeoFlow dialogues.
137
+ objects, sorting, optional children, structured leaves, object variants and
138
+ variant folders, partial animation overrides, segments, tracks, and NeoFlow
139
+ dialogues.
138
140
  - [NeoScript](references/neoscript.md): inline bodies, snippets, nullability,
139
141
  loops, switch, try/catch, ownership, evaluation, and migrations.
140
142
  - [Commands and synchronization](references/commands-and-sync.md): pull/push,
@@ -8,6 +8,7 @@ NeoFlow dialogue graphs.
8
8
  - World object contracts
9
9
  - Sorting and optional children
10
10
  - Structured leaves
11
+ - Object variants
11
12
  - Animation overrides
12
13
  - Segments and tracks
13
14
  - NeoFlow dialogues
@@ -23,6 +24,67 @@ For world layer links, derive a concrete project class from
23
24
  `targetLayer` relation. Do not add value-level target metadata or ask painting
24
25
  operations to create/repair relation targets.
25
26
 
27
+ ## Object variants
28
+
29
+ A variant is a named configuration of one `NeoObject`-derived class: how to
30
+ construct a fresh instance, and how to move an existing one into the
31
+ configuration. Variants are records parented to their class, never values
32
+ inside it, so they live in their own `Variants/` family rather than in the
33
+ class file.
34
+
35
+ ```neo
36
+ // Variants/ExampleObject.neo
37
+ @id("5f0c2b9e-7d41-4a58-9b1a-3f6f0e2d8c11")
38
+ NeoVariant<ExampleObject> Down = new(
39
+ initialize: () => { return new ExampleObject(.Down); },
40
+ apply: (source) => { source.FacingDir = .Down; },
41
+ );
42
+ ```
43
+
44
+ - `initialize` takes no parameters and returns the target class. It is
45
+ required: it is the only way to construct through the variant.
46
+ - `apply` takes exactly one parameter of the target class and is void. Omit it
47
+ for a variant that is only ever constructed.
48
+ - Both are ordinary delegate closures: parenthesized parameter list, block
49
+ body, no expression-bodied form. The server compiles them, so authored source
50
+ carries only the code.
51
+
52
+ Folders are records too, declared as their own globals and assigned per
53
+ variant. Nesting is spelled in the path with `/`; intermediate segments are
54
+ implicit, so `new("Trees/Oak")` needs no `Trees` record.
55
+
56
+ ```neo
57
+ // Variants/ExampleObject/Inverted.neo
58
+ @id("b7d2e9f0-3c15-4a68-8b24-9e0f1a2c3d44")
59
+ NeoVariantFolder<ExampleObject> Inverted = new("Inverted");
60
+
61
+ @id("e3b9c0d1-4a26-4f81-92e7-6b5a4c3d2e66")
62
+ @settings(folder: Inverted)
63
+ NeoVariant<ExampleObject> Down = new(
64
+ initialize: () => { return new ExampleObject(.Down); },
65
+ );
66
+ ```
67
+
68
+ Rules push enforces, and the language service reports live:
69
+
70
+ - A variant or folder belongs to the class its single type argument names, and
71
+ a variant may only reference a folder of its own class.
72
+ - Variant names and folder path segments share one generated static scope per
73
+ folder, and are unique within it case-insensitively. Two classes may each
74
+ declare a `Down`.
75
+ - `Base` is reserved case-insensitively: `<Class>.Variants.Base` denotes the
76
+ class with no variant applied.
77
+ - Every name must survive C# identifier normalization, since each becomes a
78
+ member of the generated `Variants` tree.
79
+
80
+ Push is folder-agnostic as it is for every other record family: a variant
81
+ declared in any `.neo` file anywhere pushes identically. `Variants/<Class>.neo`
82
+ and `Variants/<Class>/<Folder path>.neo` are the canonical layout `neo pull`
83
+ materializes, one file per (class, folder), folder record first and variants
84
+ ordered by name. `NeoVariant` and `NeoVariantFolder` are reference-only: they
85
+ declare variants as top-level globals and are never a member, entry, lookup
86
+ target, parameter, or generic-binding type.
87
+
26
88
  ## Sorting and optional children
27
89
 
28
90
  Attach `NeoSortingGroup` as an optional nested member on the project object
@@ -83,7 +83,7 @@ wrappers.
83
83
  The marker near the top of `SKILL.md` must exactly match the package version:
84
84
 
85
85
  ```html
86
- <!-- reviewed-through-cli: 0.30.3 -->
86
+ <!-- reviewed-through-cli: 0.31.1 -->
87
87
  ```
88
88
 
89
89
  The quoted version above is checked too, so this instruction cannot go stale
@@ -33,6 +33,9 @@ neo script eval --function Outpost.RefreshUnlock --this-value <id> --args '[3]'
33
33
 
34
34
  Prefer `--json` for automation.
35
35
 
36
+ Inside an inline Class body, unqualified names resolve against that Class;
37
+ invoke delegate and action members directly with `Selector()` or `OnChanged()`.
38
+
36
39
  ## Nullability and ownership
37
40
 
38
41
  Do not access a nullable receiver directly. First narrow it with a condition, or