@neocompose/cli 0.87.1 → 0.88.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.
Files changed (40) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +14 -0
  3. package/dist/neo-runtime.mjs +3789 -1141
  4. package/dist/test-worker.mjs +2450 -116
  5. package/package.json +1 -1
  6. package/skills/neocompose-cli/SKILL.md +95 -279
  7. package/skills/neocompose-cli/references/cli-development.md +101 -117
  8. package/skills/neocompose-cli/references/declarations/annotations-and-storage.md +112 -0
  9. package/skills/neocompose-cli/references/declarations/constructors.md +164 -0
  10. package/skills/neocompose-cli/references/declarations/declarations.md +103 -0
  11. package/skills/neocompose-cli/references/declarations/initializers.md +100 -0
  12. package/skills/neocompose-cli/references/declarations/member-kinds.md +107 -0
  13. package/skills/neocompose-cli/references/declarations/overloads.md +50 -0
  14. package/skills/neocompose-cli/references/dialogues.md +145 -0
  15. package/skills/neocompose-cli/references/neoscript/collections.md +98 -0
  16. package/skills/neocompose-cli/references/neoscript/control-flow.md +123 -0
  17. package/skills/neocompose-cli/references/neoscript/delegates-and-listeners.md +107 -0
  18. package/skills/neocompose-cli/references/neoscript/math-and-random.md +114 -0
  19. package/skills/neocompose-cli/references/neoscript/neoscript.md +112 -0
  20. package/skills/neocompose-cli/references/neoscript/strings.md +47 -0
  21. package/skills/neocompose-cli/references/neoscript/testing-and-migrations.md +73 -0
  22. package/skills/neocompose-cli/references/neoscript/types-and-narrowing.md +111 -0
  23. package/skills/neocompose-cli/references/sync/branches-and-history.md +69 -0
  24. package/skills/neocompose-cli/references/sync/conflicts-and-recovery.md +68 -0
  25. package/skills/neocompose-cli/references/sync/sync.md +96 -0
  26. package/skills/neocompose-cli/references/sync/unity-export.md +47 -0
  27. package/skills/neocompose-cli/references/values/defaults-and-localization.md +86 -0
  28. package/skills/neocompose-cli/references/values/files.md +71 -0
  29. package/skills/neocompose-cli/references/values/identities.md +97 -0
  30. package/skills/neocompose-cli/references/values/references.md +151 -0
  31. package/skills/neocompose-cli/references/values/values.md +110 -0
  32. package/skills/neocompose-cli/references/world/animation.md +133 -0
  33. package/skills/neocompose-cli/references/world/grids-and-cell-patterns.md +55 -0
  34. package/skills/neocompose-cli/references/world/variants.md +112 -0
  35. package/skills/neocompose-cli/references/world/world.md +105 -0
  36. package/skills/neocompose-cli/references/animation-and-world-authoring.md +0 -582
  37. package/skills/neocompose-cli/references/commands-and-sync.md +0 -408
  38. package/skills/neocompose-cli/references/declarations-and-construction.md +0 -773
  39. package/skills/neocompose-cli/references/neoscript.md +0 -990
  40. package/skills/neocompose-cli/references/values-identities-and-references.md +0 -421
@@ -1,30 +1,17 @@
1
1
  # CLI development
2
2
 
3
- Use this reference only when changing the CLI, language service, package, or
4
- the skill itself. Project authors usually do not need it.
5
-
6
- ## Contents
7
-
8
- - Source of truth
9
- - Feature-spec status
10
- - Shared implementation contract
11
- - Package and release maintenance
12
- - Verification
3
+ Read only when changing the CLI, language service, package, or this skill.
4
+ Project authors don't need it.
13
5
 
14
6
  ## Source of truth
15
7
 
16
- Treat the current CLI compiler, shared-language implementation, contract
17
- registry, tests, and generated corpus as the executable source of truth. Use
18
- the feature specs to understand intent and edge cases, but do not call the old
19
- umbrella project-source document complete: it predates P38–P52 and contains
20
- obsolete authoring examples.
21
-
22
- When a spec status header disagrees with released implementation and tests,
23
- verify the shipped package and implementation PR before teaching the feature.
24
-
25
- ## Feature-spec status
8
+ The CLI compiler, shared language implementation, contract registry, tests,
9
+ and generated corpus are the executable truth. Specs explain intent and edge
10
+ cases. When a spec's status header disagrees with the released
11
+ implementation and tests, check the shipped package and implementation PR
12
+ before teaching the feature.
26
13
 
27
- Read the relevant specs in full:
14
+ Specs to read in full when relevant:
28
15
 
29
16
  - [P38 complete schema declarations](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/complete/p38-neo-source-complete-schema-declarations.md)
30
17
  - [P39 authored system schema](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/complete/p39-neo-authored-system-schema.md)
@@ -33,8 +20,8 @@ Read the relevant specs in full:
33
20
  - [P42 structured leaf fields](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/complete/p42-addressable-structured-leaf-fields.md)
34
21
  - [P43 initializers and constructors](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/complete/p43-neoscript-initializers-and-constructors.md)
35
22
  - [P44 nested-row provenance](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/complete/p44-authored-provenance-for-nested-class-rows.md)
36
- - [P45 deferred runtime-child provenance](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/p45-provenance-for-runtime-children.md)
37
- - [P46 proposed provenance hardening](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/p46-provenance-hardening.md)
23
+ - [P45 runtime-child provenance, not implemented](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/p45-provenance-for-runtime-children.md)
24
+ - [P46 provenance hardening, proposal](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/p46-provenance-hardening.md)
38
25
  - [P47 same-push references](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/p47-same-push-value-references.md)
39
26
  - [P48 animation segments](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/p48-sprite-animation-segments.md)
40
27
  - [P49 required construction](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/p49-required-constructors-and-settled-members.md)
@@ -46,105 +33,101 @@ Read the relevant specs in full:
46
33
  - [P61 initializer materialization](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/complete/p61-initializer-materialization.md)
47
34
  - [P64 NeoScript unit testing and push hooks](https://github.com/ryanbliss/neo-compose-specs/blob/main/new-features/p64-neoscript-unit-testing-and-push-hooks.md)
48
35
 
49
- P38–P44, P47–P52, P55, P60–P61, and the initial P64 test/push-hook vertical slice
50
- are implemented. P45 remains deliberately deferred; do not
51
- build or teach runtime-child provenance. P46 is a hardening proposal, not an
52
- authoring capability. P52's document header still says proposed, but try/catch
53
- shipped in CLI 0.18; implementation and parity tests take precedence over that
54
- stale header.
55
-
56
- CLI 0.61 adds `while` and `do / while` loops, ordinal string `Replace`,
57
- ordered-list `Insert`, and method calls whose results may be discarded.
58
- See the [NeoScript reference](neoscript.md) for authoring syntax and limits.
59
-
60
- CLI 0.71 adds collection queries, negative declaration patterns, and native
61
- Debug output with authored stack traces. Compiled test caches include the
62
- relative spec path because source coordinates are part of the compiled body.
63
- Keep Debug output on stderr, including during JSON test runs.
64
-
65
- ## Shared implementation contract
66
-
67
- Manifest contracts, document comparison, normalization, and three-way merge
68
- live in `packages/manifest`. Contract generation and its registry live in
69
- `packages/manifest/schema-contract`. Web, backend, and CLI consumers import
70
- `@neocompose/manifest`; production application code must not import CLI internals.
71
-
72
- The CLI uses plain document snapshots and shared runtime functions. Keep Retree and web view models out of its imports. The headless architecture check follows CLI imports, and `cli/build.mjs` rejects UI modules and packages in the actual bundle metadata.
73
-
74
- Keep parsing, strict resolution, formatting, diagnostics with authored file and expression ranges, symbols, and
75
- NeoScript compilation in the browser-safe `@neocompose/neoscript-language`
76
- service. Monaco, VS Code, CLI, trusted server, and corpus tooling must consume
77
- that shared implementation. Do not add language intelligence to one adapter.
78
-
79
- Resolve disk formatting through the Node-only `node-format-options` entrypoint
80
- and `.editorconfig`; keep filesystem configuration out of browser imports.
81
- Format regenerated source before compiling it so cached source ranges match
82
- the written files. Preserve authored source when a push changes no source tokens.
83
-
84
- Keep evaluation in `@neocompose/neoscript-runtime` and shared schema/value
85
- contracts in `@neocompose/models`. Models depend on language and manifest;
86
- runtime depends on those packages. App context projection, database adapters,
87
- and reactive hosts remain in the app. Packages must not import host code.
88
- Boundary and import-cycle checks run with `npm run lint:architecture`;
89
- `npm run test:runtime-package` checks a standalone custom database host.
90
-
91
- Keep project context refreshable without accumulating stale Monaco providers or
92
- LSP state. Preserve diagnostics, completion, hover, signatures, definition,
93
- references, implementations, rename, symbols, semantic tokens, code actions, and formatting
94
- parity for `.neo` and `.neoflow`.
95
-
96
- The CLI prepares every push with the server's own preparation code: it
97
- compiles changed NeoScript bodies and callers affected by schema-contract
98
- changes, materializes values, and validates the whole graph against the pulled
99
- head. The server accepts that preparation only from a CLI on its NeoScript
100
- compiler revision and re-checks the head, authorization, row shapes, and CAS
101
- bases. A modified CLI can therefore write bad rows to a project its user may
102
- already write; keep preparation in shared `src/database` code rather than
103
- forking it in the CLI. The server still verifies a push's uploaded
104
- project-file bytes, and web editor commits use the shared client preparation protocol.
105
- Unrelated source files are not uploaded or recompiled on every push.
106
- Optional source maps missing from valid stored bodies do not request a backfill.
107
- Formatting-only source location changes do not create pushes, including when
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,
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
113
- canonical pull; `neo push --dry-run` remains the complete source-to-record
114
- rehearsal.
115
-
116
- A committed push result is journaled in `.neo/state.json` before source
117
- projection. If projection fails, `neo pull` consumes that result and preserves
118
- later local edits before fetching newer remote changes. Do not advance the merge
119
- base without preserving recovery, or retry the write as a new push. Candidate
120
- value projection shares the push envelope completion; persisted physical rows
121
- and content hashes remain the merge base.
36
+ ## Package boundaries
37
+
38
+ - Manifest contracts, document comparison, normalization, and three-way merge
39
+ live in `packages/manifest`; contract generation in
40
+ `packages/manifest/schema-contract`. Consumers import
41
+ `@neocompose/manifest`. Production app code never imports CLI internals.
42
+ - The CLI uses plain document snapshots and shared runtime functions. Retree
43
+ and web view models stay out; the headless architecture check and
44
+ `cli/build.mjs` reject UI modules in the bundle.
45
+ - Parsing, resolution, formatting, diagnostics with authored ranges, symbols,
46
+ and NeoScript compilation live in the browser-safe
47
+ `@neocompose/neoscript-language`. Monaco, VS Code, CLI, server, and corpus
48
+ tooling all consume it; never add language intelligence to one adapter.
49
+ Keep diagnostics, completion, hover, signatures, navigation, rename,
50
+ symbols, semantic tokens, code actions, and formatting at parity for
51
+ `.neo` and `.neoflow`, and keep project context refreshable without stale
52
+ Monaco providers or LSP state.
53
+ - Disk formatting goes through the Node-only `node-format-options` entrypoint
54
+ and `.editorconfig`. Format regenerated source before compiling so cached
55
+ ranges match written files.
56
+ - Evaluation lives in `@neocompose/neoscript-runtime`, schema/value contracts
57
+ in `@neocompose/models`. Models depend on language and manifest; runtime on
58
+ those. App context projection, database adapters, and reactive hosts stay
59
+ in the app. `npm run lint:architecture` checks boundaries and cycles;
60
+ `npm run test:runtime-package` checks a standalone database host.
61
+ - Compiled test caches include the relative spec path because source
62
+ coordinates are part of the compiled body. Debug output stays on stderr,
63
+ including in JSON test runs.
64
+
65
+ ## Push preparation
66
+
67
+ The CLI prepares every push with the server's own preparation code: compile
68
+ changed bodies and schema-affected callers, materialize values, validate the
69
+ whole graph against the pulled head. The server accepts that preparation only
70
+ from a CLI on its NeoScript compiler revision and re-checks head,
71
+ authorization, row shapes, CAS bases, and uploaded file bytes. A modified CLI
72
+ can therefore write bad rows to a project its user may already write, so keep
73
+ preparation in shared `src/database` code instead of forking it. Web editor
74
+ commits use the shared client preparation protocol.
75
+
76
+ - Unchanged source files are neither uploaded nor recompiled. Changed bodies
77
+ share one schema projection; each compiles once for local evaluation and
78
+ once against minted IDs.
79
+ - Formatting-only location changes create no push. Stored initializer
80
+ recipes, computed defaults, and inline constructor delegates keep pulled
81
+ code and compiled bodies when tokens are unchanged; string content still
82
+ counts. Missing optional source maps don't request a backfill.
83
+ - Push hashes the authored inputs it read (paths and formatting included);
84
+ the same bytes and base keep reconnect identity across candidate UUID
85
+ allocation.
86
+ - Durable preparation is chosen from the semantic record workload. Staging
87
+ reads one plan per bounded batch with an atomic write per physical chunk.
88
+ - Each command uses one authenticated Convex websocket. Push sends compressed
89
+ JSON through `clientCommits.commit` when there are no staged files and it
90
+ decodes to at most 512 KiB; otherwise it streams `begin`, `appendChunks`,
91
+ and `seal`. The CLI pins the deployment through the authenticated app
92
+ origin before sending a session token.
93
+ - A committed result is journaled in `.neo/state.json` before source
94
+ projection. Never advance the merge base without preserving recovery, and
95
+ never retry the write as a new push. Further result pages are downloaded
96
+ and counted before the base advances; edits made while waiting trigger fresh
97
+ analysis.
98
+ - Full pulls size pages to Convex limits, fetch ranges concurrently, and pin
99
+ every page to one published generation and logical revision, restarting if
100
+ either changes. Undo/reset metadata changes invalidate the incremental
101
+ cursor and fall back to a full snapshot.
122
102
 
123
103
  ## Package and release maintenance
124
104
 
125
- Keep the npm artifact native JavaScript. Do not publish `.csproj`, `.cs`,
126
- `.dll`, Roslyn host metadata, generated C# SDK output, or trusted server-only
127
- wrappers.
105
+ Publish native JavaScript only: no `.csproj`, `.cs`, `.dll`, Roslyn host
106
+ metadata, generated C# SDK output, or trusted server-only wrappers.
128
107
 
129
- The marker near the top of `SKILL.md` must exactly match the package version:
108
+ The marker near the top of `SKILL.md` must exactly match the package version,
109
+ and this quoted copy is checked too:
130
110
 
131
111
  ```html
132
- <!-- reviewed-through-cli: 0.87.1 -->
112
+ <!-- reviewed-through-cli: 0.88.0 -->
133
113
  ```
134
114
 
135
- The quoted version above is checked too, so this instruction cannot go stale
136
- while the skill advances.
115
+ Keep this skill on current behavior. Upgrade steps, rollout prerequisites,
116
+ and release history belong in release notes.
137
117
 
138
- For every CLI behavior change, audit the affected skill/references in the same
139
- feature PR and add a unique `.changeset/*.md` release note. Leave versions,
140
- changelogs, and these markers unchanged. `npm run version:packages` combines
141
- fragments in a release PR and advances the markers after those feature reviews.
142
- `npm run doctor` and package verification still check marker/version agreement
143
- and the newest changelog entry. See `.changeset/README.md` in the repository.
118
+ For every CLI behavior change, update the affected skill pages in the same
119
+ feature PR and add a unique `.changeset/*.md`. Leave versions, changelogs,
120
+ and markers alone; `npm run version:packages` advances them in the release
121
+ PR. `npm run doctor` and package verification check marker/version agreement
122
+ and the newest changelog entry. See `.changeset/README.md`.
144
123
 
145
- Keep `agents/openai.yaml` and every directly linked reference inside the
146
- published `skills/neocompose-cli/` tree. Keep the frontmatter limited to
147
- `name` and `description`.
124
+ Skill layout: `SKILL.md` links domain pages, and each domain page links its
125
+ own leaves. Put new detail in the narrowest leaf that owns the API, and keep
126
+ `SKILL.md` and domain pages to rules that apply across their branch. Every
127
+ Markdown file must be reachable from `SKILL.md` by relative links inside the
128
+ published `skills/neocompose-cli/` tree; `npm --prefix cli run skill:check`
129
+ and package verification enforce it. Keep `agents/openai.yaml` in that tree.
130
+ Frontmatter holds only `name` and `description`.
148
131
 
149
132
  ## Verification
150
133
 
@@ -152,14 +135,15 @@ Run focused language/compiler tests for changed behavior, then:
152
135
 
153
136
  ```sh
154
137
  python3 <skill-creator>/scripts/quick_validate.py cli/skills/neocompose-cli
138
+ npm --prefix cli run skill:check
155
139
  npm --prefix cli run test:package
156
140
  npm run typecheck
157
141
  npm run doctor
158
142
  ```
159
143
 
160
144
  Also run contract/corpus checks, Monaco/browser parity, VSIX packaging, and
161
- interactive sample no-op verification when the corresponding implementation
162
- surface changes. Evaluator or candidate-materialization changes also require an
163
- actual `neo test` run against the affected full-project candidate; focused
164
- Vitest coverage does not replace that end-to-end command. Run `npm run doctor`
165
- last; do not rerun successful suites only because doctor formatted files.
145
+ interactive sample no-op checks when those implementations change. Evaluator
146
+ or candidate-materialization changes also need a real `neo test` against the
147
+ affected full-project candidate; Vitest doesn't replace it. Run
148
+ `npm run doctor` last, and don't rerun passing suites just because doctor
149
+ formatted files.
@@ -0,0 +1,112 @@
1
+ # Annotations and storage
2
+
3
+ Typed annotations on declarations and members. Never author `@system`; system
4
+ types visible in source may carry it, which does not license copying it. Keep
5
+ annotations separate rather than inventing a metadata bag, and use numeric
6
+ literals for numeric limits.
7
+
8
+ ## Annotation list
9
+
10
+ - `@settings(...)`: format, search, collection, and editor constraints. Use
11
+ contextual enum cases: `@settings(format: .Plain)`,
12
+ `@settings(kind: .Unordered)`. Before a `List`/`Set` element or `Dictionary`
13
+ value type it configures entries:
14
+ `List<@settings(format: .Plain) string>`,
15
+ `Dictionary<string, @settings(min: 0) int>`. Only the declaring member spells
16
+ entry settings; overrides share them.
17
+ - `@storage(allowed: ...)`: on classes and members. See [Storage](#storage).
18
+ - `@visibility(.Hidden)`: classes only; absence means visible.
19
+ - `@relations(...)`: only on the source class of a specialized direct
20
+ relation.
21
+ - `@distribution(kind: .Sparse | .Packed)`: only on a value-owning member or
22
+ override. `.Sparse` gives the value its own row; `.Packed` stores it in the
23
+ parent's row and shares the parent's document-size limit (an oversized
24
+ write fails). Omit it unless the choice must be explicit: absence means
25
+ automatic on a declaration and inherit on an override. `.Packed` is
26
+ rejected on an unordered List.
27
+ - `@effect`: on an immediate, parameterless `void` instance function with a
28
+ NeoScript or abstract body. Unity runs it for every live instance and reruns
29
+ it when data it read changes; the web editor, `neo test`, and dry runs never
30
+ run it. Overrides inherit it; `@effect(kind: .None)` stops it. Prefer it to
31
+ polling or hand-relayed changes.
32
+ - `@index(member: Field, kind: .Unique)` and `@column(member: Field, ...)`
33
+ with `width`, `visibility`, `pin`, and `overflow`: repeatable List
34
+ annotations naming a bare entry-class field. An index takes a non-localizable string or single-select
35
+ enum. A column may target `__other__` for subclass-added fields. Declare
36
+ indexes only on the original List member; `@index` on an override is an
37
+ error. A List field may override an abstract List getter.
38
+ - `@listeners(...)`: see
39
+ [delegates and listeners](../neoscript/delegates-and-listeners.md#persisted-wiring).
40
+
41
+ Defaults and settings must be statically analyzable. Enum initializer errors
42
+ are reported at the authored expression, including inside extracted locals
43
+ and for missing dictionary option keys.
44
+
45
+ ## Storage
46
+
47
+ Member `@storage(allowed:)` is `.Immutable`, `.Save`, `.Session`, or
48
+ `.Writable`; omit it to inherit the placement parent's storage.
49
+
50
+ `.Writable` is always runtime-writable and resolves by placement: Save under
51
+ a Save parent, Session under a Session or Immutable parent. Use it for
52
+ members that NeoScript or animation clips write and that should persist
53
+ exactly when their owner does.
54
+
55
+ ```neo
56
+ class AnimationSpriteObject(SpriteInfo sprite) : NeoSpriteObject {
57
+ @storage(allowed: .Writable)
58
+ public override Vector3 Size = new(1, 1, 0);
59
+ }
60
+ ```
61
+
62
+ - Overrides below a `.Writable` member may be `.Writable`, `.Save`,
63
+ `.Session`, or omitted; never `.Immutable`, `.Inherit`, or `readonly`.
64
+ - Statics, `readonly` members, and project roots can't be `.Writable`.
65
+ - On a class, `.Writable` means every placement resolves to Save or Session.
66
+ Subclasses may narrow to `.Save` or `.Session`. Undeclared statics of such a
67
+ class are Session.
68
+
69
+ ## User data
70
+
71
+ `root.User` holds per-player data shared by every save, such as settings.
72
+ Only User classes go there:
73
+
74
+ ```neo
75
+ @storage(allowed: .User)
76
+ class AudioPrefs {
77
+ public float Volume = 1;
78
+ }
79
+ ```
80
+
81
+ - Base and subclasses must also be User classes.
82
+ - Members declare no `@storage` and no stored statics. Every named type must
83
+ be User-safe: primitives, enums, User classes, collections and delegates of
84
+ those, and interfaces with User-safe signatures.
85
+ - Code in a User class reads only `root.User`. Other code may read
86
+ `root.User` but not assign, mutate, construct, or invoke User data.
87
+ - Lookups and listeners don't cross between User and Save data; Session
88
+ lookups may target `root.User`.
89
+
90
+ ## readonly and constants
91
+
92
+ `readonly` is C# init-only and independent of storage. A field initializer,
93
+ constructor body, object initializer, or authored value sets it; nothing
94
+ writes it later. It's valid on Save, Session, Immutable, and User classes,
95
+ not with Writable, and may read header parameters:
96
+
97
+ ```neo
98
+ class MixerGroup(string name) {
99
+ public readonly string Name = name;
100
+ public readonly List<MixerChannel> Children = [];
101
+ }
102
+ ```
103
+
104
+ Readonly is shallow: a readonly collection's membership is fixed, entries
105
+ follow their own rules.
106
+
107
+ A readonly member declared as a literal (no initializer or constructor call) that
108
+ reads neither `this` nor constructor arguments and holds nothing writable is
109
+ a constant: instances share it and store nothing until a constructor or
110
+ initializer writes it. Readonly collections and initializers still build per
111
+ instance. Immutable member constants are covered in
112
+ [initializers](initializers.md#immutable-members).
@@ -0,0 +1,164 @@
1
+ # Constructors
2
+
3
+ Header and declared constructors, settlement, parameter defaults, and
4
+ inheritance. Member defaults are in [initializers](initializers.md).
5
+
6
+ ## Header constructors
7
+
8
+ Put one required constructor on the class header when the whole body needs
9
+ its parameters:
10
+
11
+ ```neo
12
+ class Foo(string bar, bool isFun) {
13
+ public string Bar = bar;
14
+ public bool IsFun;
15
+
16
+ init {
17
+ IsFun = isFun;
18
+ }
19
+ }
20
+
21
+ Foo value = new(bar: "BAR", isFun: true) { IsFun = false };
22
+ ```
23
+
24
+ - Header parameters are in scope in every instance member. Field
25
+ initializers, collection entries, object initializers, and lambdas read them
26
+ per construction, so `public NeoDelegate<int> Value = () => n;` returns each
27
+ instance's own `n`. A lambda may also read `this` (`() => n + this.M`); the
28
+ rest of an initializer can't.
29
+ - Statics can't read header parameters.
30
+ - At most one `init` block.
31
+ - A header constructor disables implicit parameterless `new` and forbids
32
+ other constructor overloads. Its derived identity takes no `@id`.
33
+
34
+ ## Declared constructors
35
+
36
+ Declare overloadable constructors as members when each body owns its own
37
+ parameters:
38
+
39
+ ```neo
40
+ class Foo {
41
+ public string Bar;
42
+ public bool IsFun;
43
+
44
+ public Foo(string bar, bool isFun) {
45
+ this.Bar = bar;
46
+ this.IsFun = isFun;
47
+ }
48
+ }
49
+ ```
50
+
51
+ Their parameters are visible only in that body, never in member initializers.
52
+ Each declared constructor must settle every required member itself; a
53
+ call-site block can't repair an invalid constructor.
54
+
55
+ ## Required members and settlement
56
+
57
+ ```neo
58
+ class Result {
59
+ public string Value; // required
60
+ public bool Ok = true; // settled by default
61
+ public string? Note; // settled by implicit null
62
+ }
63
+ ```
64
+
65
+ A required member is settled only by:
66
+
67
+ 1. its own initializer,
68
+ 2. assignment on every reachable path of `init` or a constructor body (full
69
+ `if`/`else` coverage), or
70
+ 3. a call-site initializer entry on an otherwise valid construction.
71
+
72
+ Side effects inside other functions never count.
73
+
74
+ Construction order: base construction, member initializers, `init` or
75
+ constructor body, then the call-site block, which wins where it refines an
76
+ earlier value. Call-site blocks may set `readonly` members of the new
77
+ instance, including nested `new` expressions.
78
+
79
+ When a construction leaves a member unsettled, the diagnostic points at `new`
80
+ with the member declaration as a related location. Unrelated valid root
81
+ initializers still take part in reference checking.
82
+
83
+ ## Parameter defaults
84
+
85
+ ```neo
86
+ class Foo(string bar = "BAR", int volume = 3) {
87
+ public string Bar = bar;
88
+ public string Shout(string text = "hey", bool loud = true) {
89
+ return loud ? text.ToUpper() : text;
90
+ }
91
+ }
92
+
93
+ Foo a = new(); // all defaults
94
+ Foo b = new(bar: "bar"); // volume defaults
95
+ ```
96
+
97
+ - Allowed on class headers, declared constructors, native functions,
98
+ NSFunctions, and interface functions. Not on deferred functions, delegates,
99
+ actions, closures, or overrides.
100
+ - Constants only: bool/int/float/decimal literals (optional leading `-`),
101
+ non-interpolated strings, `.Option` enum literals, and `null` on a nullable
102
+ parameter. Defaulted parameters come last. `Type? name` without a default is
103
+ still mandatory.
104
+ - Function calls drop only a trailing suffix; constructor calls name any
105
+ subset covering the non-defaulted parameters. Interface implementations
106
+ restate defaults exactly.
107
+ - Enum defaults store the option ID, so renaming the option only changes the
108
+ emitted spelling.
109
+
110
+ ## Inheritance
111
+
112
+ ```neo
113
+ class Base(string name) {
114
+ public string Name = name;
115
+ }
116
+
117
+ class Child(string name, int rank) : Base(name) {
118
+ public int Rank = rank;
119
+ }
120
+ ```
121
+
122
+ When the base has no constructor, settle its required members in a base
123
+ initializer block:
124
+
125
+ ```neo
126
+ class Child(string name) : Base {
127
+ Name = name,
128
+ Enabled = false
129
+ } {
130
+ }
131
+ ```
132
+
133
+ - `: Base()` or `: Base` runs a zero-argument or fully defaulted base
134
+ constructor when one exists. If the base has only declared constructors, it
135
+ uses member initializers and the base block without a base constructor. A
136
+ required base constructor can't be skipped. A declared constructor's
137
+ `: base()` must call one when the base declares one.
138
+ - A subclass that omits required base arguments or leaves an inherited
139
+ required member unsettled is rejected. Bind generic base arguments
140
+ explicitly when needed.
141
+ - Base-constructor arguments use the constructed class's concrete generic
142
+ bindings, including an `Item<T>` parameter forwarded through its base chain.
143
+ - Constraints may construct another generic from a sibling parameter:
144
+
145
+ ```neo
146
+ class PlacedItem<
147
+ TData extends InventoryStackData,
148
+ TItem extends InventoryItem<TData>
149
+ >(TItem item) {
150
+ public TData Data = item.DefaultData.Clone();
151
+ }
152
+ ```
153
+
154
+ ## Object initializer syntax
155
+
156
+ Entries are separated by commas; a trailing comma is optional. A semicolon
157
+ inside the braces is an error; one after the closing brace ends the
158
+ declaration:
159
+
160
+ ```neo
161
+ AudioSettings AUDIO_SETTINGS = new() {
162
+ Main = new AudioMixerGroupSettingsFolder("Main", "Master", "MasterVolume", []),
163
+ };
164
+ ```
@@ -0,0 +1,103 @@
1
+ # Declarations
2
+
3
+ Rules for classes, interfaces, enums, and members. Open a leaf from
4
+ [References](#references) for annotations, constructors, special member
5
+ kinds, or overloads.
6
+
7
+ ## Shape
8
+
9
+ Declare classes, interfaces, and enums only at the top level of definition
10
+ `.neo` files, never inside a type, body, accessor, lambda, initializer,
11
+ migration, or `.neoflow` file (NeoFlow has its own single-dialogue rule). The
12
+ declared identifier is the schema name; there is no separate display name.
13
+
14
+ ```neo
15
+ @id("interface-named-id")
16
+ interface INamed {
17
+ @id("named-name-id")
18
+ string Name { get; }
19
+
20
+ @id("named-use-id")
21
+ void Use(SomeClass context);
22
+ }
23
+
24
+ @id("class-item-id")
25
+ @storage(allowed: .Immutable)
26
+ abstract class Item<TContext extends SomeClass> : INamed {
27
+ @id("item-name-id")
28
+ @settings(searchBy: .MemberKey)
29
+ public virtual string Name = "";
30
+
31
+ @id("item-use-id")
32
+ public abstract void Use(TContext context);
33
+
34
+ @id("item-load-id")
35
+ public native async bool Load(TContext context);
36
+ }
37
+ ```
38
+
39
+ The `@id`s above are pulled IDs. New declarations omit them; push assigns them.
40
+ Never put `@id` on inferred list/dictionary entry types or derived structural
41
+ descriptors.
42
+
43
+ ## Modifiers
44
+
45
+ `public`, `protected`, `private`, `static`, `virtual`, `abstract`, `sealed`,
46
+ and `override` follow C#.
47
+
48
+ - `sealed`: an instantiable leaf. It may extend a class, can't be extended or
49
+ abstract, and can be sealed only while it has no subclasses.
50
+ - `closed`: implicitly abstract, an exhaustive subtype family for switch
51
+ expressions. Don't combine with `abstract` or `sealed`. Descendants stay open
52
+ unless sealed or closed. Every generic parameter of a direct subclass must
53
+ appear in its base construction.
54
+ - A read-only override may narrow a class or interface contract to an
55
+ assignable class or derived interface, or to non-null. Generated C# keeps
56
+ the inherited type.
57
+
58
+ ## Members
59
+
60
+ - Kind and optionality come from the type and its nullability. The
61
+ initializer is the default.
62
+ - A non-null member without a default is required. A nullable member without
63
+ a default is implicitly `null`. See
64
+ [constructors](constructors.md#required-members-and-settlement).
65
+ - Omitted fields of an instance stay virtual and track later default edits
66
+ until overridden. See [defaults and overrides](../values/defaults-and-localization.md).
67
+ - Use `.Case` only where context fixes one enum type, otherwise
68
+ `EnumType.Case`. Constructor parameters supply that context, including
69
+ substituted generic types. An integer is not an enum option.
70
+ - An explicit construction must be assignable to its receiving type,
71
+ generic arguments included.
72
+
73
+ ## Names
74
+
75
+ Keywords are case-sensitive. Qualified member labels, schema keys, registry
76
+ entries, and enum options live in their owner's namespace and may reuse
77
+ builtin names such as `Set`, `List`, or `Math`; `Set` and `Dictionary` are also
78
+ legal parameter names. Grammar keywords stay reserved. Top-level declarations
79
+ and bindings may not shadow `Math`, and `this`, `root`, and `context` can't be
80
+ parameters.
81
+
82
+ ## Relations
83
+
84
+ Keep generic project relations as typed top-level declarations in
85
+ `Relations.neo`; the compiler derives owned descriptor and generic binding
86
+ identities. A world layer link is a project subclass of `NeoTileLayerLink` or
87
+ `NeoObjectLayerLink` that resolves exactly one `targetLayer` relation. The
88
+ relation is the whole binding; add no value-level target metadata.
89
+
90
+ ## References
91
+
92
+ - [Annotations and storage](annotations-and-storage.md): `@settings`,
93
+ `@storage` (Save/Session/Writable/User), `readonly` and constants,
94
+ `@index`/`@column`, `@distribution`, `@effect`, `@visibility`.
95
+ - [Constructors](constructors.md): header and declared constructors, `init`,
96
+ required-member settlement, parameter defaults, inheritance.
97
+ - [Initializers](initializers.md): member defaults, what they may read,
98
+ computed defaults, generic and Immutable construction, stored-construction
99
+ edits.
100
+ - [Member kinds](member-kinds.md): interface-typed members, `Set<T>`,
101
+ `NeoAction`, lifecycle interfaces, stored tuples.
102
+ - [Overloads](overloads.md): declaring overloads and how calls pick one.
103
+ - [References](../values/references.md): `Reference<T>` lookup members.