@neocompose/cli 0.87.2 → 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.
- package/CHANGELOG.md +12 -0
- package/README.md +14 -0
- package/dist/neo-runtime.mjs +3288 -724
- package/dist/test-worker.mjs +2445 -114
- package/package.json +1 -1
- package/skills/neocompose-cli/SKILL.md +95 -279
- package/skills/neocompose-cli/references/cli-development.md +101 -117
- package/skills/neocompose-cli/references/declarations/annotations-and-storage.md +112 -0
- package/skills/neocompose-cli/references/declarations/constructors.md +164 -0
- package/skills/neocompose-cli/references/declarations/declarations.md +103 -0
- package/skills/neocompose-cli/references/declarations/initializers.md +100 -0
- package/skills/neocompose-cli/references/declarations/member-kinds.md +107 -0
- package/skills/neocompose-cli/references/declarations/overloads.md +50 -0
- package/skills/neocompose-cli/references/dialogues.md +145 -0
- package/skills/neocompose-cli/references/neoscript/collections.md +98 -0
- package/skills/neocompose-cli/references/neoscript/control-flow.md +123 -0
- package/skills/neocompose-cli/references/neoscript/delegates-and-listeners.md +107 -0
- package/skills/neocompose-cli/references/neoscript/math-and-random.md +114 -0
- package/skills/neocompose-cli/references/neoscript/neoscript.md +112 -0
- package/skills/neocompose-cli/references/neoscript/strings.md +47 -0
- package/skills/neocompose-cli/references/neoscript/testing-and-migrations.md +73 -0
- package/skills/neocompose-cli/references/neoscript/types-and-narrowing.md +111 -0
- package/skills/neocompose-cli/references/sync/branches-and-history.md +69 -0
- package/skills/neocompose-cli/references/sync/conflicts-and-recovery.md +68 -0
- package/skills/neocompose-cli/references/sync/sync.md +96 -0
- package/skills/neocompose-cli/references/sync/unity-export.md +47 -0
- package/skills/neocompose-cli/references/values/defaults-and-localization.md +86 -0
- package/skills/neocompose-cli/references/values/files.md +71 -0
- package/skills/neocompose-cli/references/values/identities.md +97 -0
- package/skills/neocompose-cli/references/values/references.md +151 -0
- package/skills/neocompose-cli/references/values/values.md +110 -0
- package/skills/neocompose-cli/references/world/animation.md +133 -0
- package/skills/neocompose-cli/references/world/grids-and-cell-patterns.md +55 -0
- package/skills/neocompose-cli/references/world/variants.md +112 -0
- package/skills/neocompose-cli/references/world/world.md +105 -0
- package/skills/neocompose-cli/references/animation-and-world-authoring.md +0 -582
- package/skills/neocompose-cli/references/commands-and-sync.md +0 -408
- package/skills/neocompose-cli/references/declarations-and-construction.md +0 -773
- package/skills/neocompose-cli/references/neoscript.md +0 -990
- package/skills/neocompose-cli/references/values-identities-and-references.md +0 -421
|
@@ -1,30 +1,17 @@
|
|
|
1
1
|
# CLI development
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
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
|
|
37
|
-
- [P46
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
`@neocompose/
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
126
|
-
|
|
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.
|
|
112
|
+
<!-- reviewed-through-cli: 0.88.0 -->
|
|
133
113
|
```
|
|
134
114
|
|
|
135
|
-
|
|
136
|
-
|
|
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,
|
|
139
|
-
feature PR and add a unique `.changeset/*.md
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
`
|
|
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
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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.
|