@neocompose/cli 0.68.3 → 0.68.4
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 +4 -0
- package/dist/neo.mjs +47 -21
- package/dist/test-worker.mjs +2 -0
- package/package.json +1 -1
- package/skills/neocompose-cli/SKILL.md +1 -1
- package/skills/neocompose-cli/references/cli-development.md +1 -1
- package/skills/neocompose-cli/references/declarations-and-construction.md +8 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.68.4] - 2026-10-05
|
|
4
|
+
|
|
5
|
+
- An empty header base clause such as `class Child(string name) : Base() { Name = name } {}` uses the base's member initializers when its declared constructors require arguments. The base block must settle remaining required members. Zero-argument and fully defaulted base constructors still run; required base constructors and declared `: base()` calls still require valid arguments. Fixes [#1186](https://github.com/ryanbliss/neo-compose/issues/1186). Use SDK 0.57.4 for matching Unity runtime behavior.
|
|
6
|
+
|
|
3
7
|
## [0.68.3] - 2026-10-05
|
|
4
8
|
|
|
5
9
|
- `neo push --dry-run` preserves valid authored UUID-v4 IDs on new nested member and dictionary values, including values named by local declarations. Previously, verification dropped the ID and failed with an internal "has no pending id assignment" error. Status and push report malformed new member-value IDs at the annotation, name the affected `Class.Member`, and suggest removing `@id` or providing an unused UUID v4 ([#1189](https://github.com/ryanbliss/neo-compose/issues/1189)).
|
package/dist/neo.mjs
CHANGED
|
@@ -22862,6 +22862,11 @@ var init_project_source_variants = __esm({
|
|
|
22862
22862
|
});
|
|
22863
22863
|
|
|
22864
22864
|
// ../packages/neoscript-language/src/project-source-settlement.ts
|
|
22865
|
+
function requiredConstructorParameters(declaration) {
|
|
22866
|
+
if (declaration.headerParameters !== void 0)
|
|
22867
|
+
return declaration.headerParameters;
|
|
22868
|
+
return declaration.initBlocks.length > 0 ? [] : void 0;
|
|
22869
|
+
}
|
|
22865
22870
|
function buildNeoConstructionIndex(documents) {
|
|
22866
22871
|
const classes = /* @__PURE__ */ new Map();
|
|
22867
22872
|
const interfaceNames = /* @__PURE__ */ new Set();
|
|
@@ -22933,8 +22938,9 @@ function unsettledRequiredMembers(index, className, settledNames, typeArguments
|
|
|
22933
22938
|
function classConstructionContract(index, className) {
|
|
22934
22939
|
const declaration = index.classes.get(className)?.declaration;
|
|
22935
22940
|
if (!declaration) return null;
|
|
22936
|
-
|
|
22937
|
-
|
|
22941
|
+
const parameters = requiredConstructorParameters(declaration);
|
|
22942
|
+
if (parameters !== void 0) {
|
|
22943
|
+
return { kind: "required", parameters };
|
|
22938
22944
|
}
|
|
22939
22945
|
if (declaration.constructors.length > 0) {
|
|
22940
22946
|
return { kind: "declared", constructors: declaration.constructors };
|
|
@@ -22998,7 +23004,7 @@ function validateBaseConstruction(index, entry, diagnostics) {
|
|
|
22998
23004
|
}
|
|
22999
23005
|
for (const diagnostic of validateNeoConstructionSite(index, {
|
|
23000
23006
|
className: baseClause.type.name,
|
|
23001
|
-
site: "
|
|
23007
|
+
site: "headerBase",
|
|
23002
23008
|
typeArguments: baseClause.type.typeArguments.map(typeShape),
|
|
23003
23009
|
argumentNames: (baseClause.arguments ?? []).map(
|
|
23004
23010
|
(argument2) => argument2.name ?? null
|
|
@@ -23024,11 +23030,10 @@ function validateBaseConstruction(index, entry, diagnostics) {
|
|
|
23024
23030
|
}
|
|
23025
23031
|
}
|
|
23026
23032
|
function validateUnconstructedBase(entry, base, range2, diagnostics) {
|
|
23027
|
-
const parameters = base.declaration
|
|
23033
|
+
const parameters = requiredConstructorParameters(base.declaration);
|
|
23028
23034
|
if (parameters === void 0) {
|
|
23029
|
-
if (entry.declaration
|
|
23030
|
-
|
|
23031
|
-
pushBaseCall(entry, base, [], () => range2, diagnostics);
|
|
23035
|
+
if (requiredConstructorParameters(entry.declaration) === void 0) return;
|
|
23036
|
+
pushBaseCall(entry, base, [], () => range2, diagnostics, "headerBase");
|
|
23032
23037
|
return;
|
|
23033
23038
|
}
|
|
23034
23039
|
if (parameterListIsFullyDefaulted(parameters)) return;
|
|
@@ -23047,7 +23052,7 @@ function validateUnconstructedBase(entry, base, range2, diagnostics) {
|
|
|
23047
23052
|
function validateDeclaredBaseCalls(entry, base, diagnostics) {
|
|
23048
23053
|
for (const constructor2 of entry.declaration.constructors) {
|
|
23049
23054
|
const baseArguments = constructor2.baseArguments ?? [];
|
|
23050
|
-
if (constructor2.baseArguments === void 0 && base.declaration
|
|
23055
|
+
if (constructor2.baseArguments === void 0 && requiredConstructorParameters(base.declaration) !== void 0) {
|
|
23051
23056
|
continue;
|
|
23052
23057
|
}
|
|
23053
23058
|
pushBaseCall(
|
|
@@ -23062,13 +23067,13 @@ function validateDeclaredBaseCalls(entry, base, diagnostics) {
|
|
|
23062
23067
|
);
|
|
23063
23068
|
}
|
|
23064
23069
|
}
|
|
23065
|
-
function pushBaseCall(entry, base, argumentNames, rangeOf, diagnostics) {
|
|
23070
|
+
function pushBaseCall(entry, base, argumentNames, rangeOf, diagnostics, site = "base") {
|
|
23066
23071
|
const siteDiagnostics = [];
|
|
23067
23072
|
resolveInvokedConstructor(
|
|
23068
23073
|
base.declaration,
|
|
23069
23074
|
{
|
|
23070
23075
|
className: base.declaration.name,
|
|
23071
|
-
site
|
|
23076
|
+
site,
|
|
23072
23077
|
argumentNames,
|
|
23073
23078
|
initializerNames: []
|
|
23074
23079
|
},
|
|
@@ -23127,7 +23132,7 @@ function validateDeclaredConstructionPaths(index, entry, diagnostics) {
|
|
|
23127
23132
|
[]
|
|
23128
23133
|
).filter((member) => owned || member.declaringClassName === declaration.name);
|
|
23129
23134
|
if (outstanding.length === 0) return;
|
|
23130
|
-
if (declaration
|
|
23135
|
+
if (requiredConstructorParameters(declaration) !== void 0) {
|
|
23131
23136
|
const initBlock = declaration.initBlocks[0];
|
|
23132
23137
|
const assigned = assignedOnEveryPath(initBlock?.body.text ?? "{}");
|
|
23133
23138
|
const unsettled = filterUnassigned(outstanding, assigned);
|
|
@@ -23168,13 +23173,30 @@ function filterUnassigned(members, assigned) {
|
|
|
23168
23173
|
}
|
|
23169
23174
|
function declarationSettledMembers(index, entry) {
|
|
23170
23175
|
const settled = /* @__PURE__ */ new Set();
|
|
23171
|
-
const
|
|
23172
|
-
|
|
23173
|
-
for (const field of baseClause
|
|
23176
|
+
const declaration = entry.declaration;
|
|
23177
|
+
const baseClause = declaration.baseClause;
|
|
23178
|
+
for (const field of baseClause?.initializerFields ?? []) {
|
|
23174
23179
|
settled.add(field.name.toLowerCase());
|
|
23175
23180
|
}
|
|
23176
|
-
if (
|
|
23177
|
-
|
|
23181
|
+
if (baseClause === void 0 && requiredConstructorParameters(declaration) === void 0)
|
|
23182
|
+
return settled;
|
|
23183
|
+
const baseName = baseClause?.type.name ?? declaration.baseTypes[0]?.name;
|
|
23184
|
+
const base = baseName === void 0 ? void 0 : index.classes.get(baseName);
|
|
23185
|
+
if (base === void 0) return settled;
|
|
23186
|
+
if (!resolveInvokedConstructor(
|
|
23187
|
+
base.declaration,
|
|
23188
|
+
{
|
|
23189
|
+
className: base.declaration.name,
|
|
23190
|
+
site: "headerBase",
|
|
23191
|
+
argumentNames: (baseClause?.arguments ?? []).map(
|
|
23192
|
+
(argument2) => argument2.name ?? null
|
|
23193
|
+
),
|
|
23194
|
+
initializerNames: []
|
|
23195
|
+
},
|
|
23196
|
+
[]
|
|
23197
|
+
))
|
|
23198
|
+
return settled;
|
|
23199
|
+
for (const member of requiredMembersForClass(index, base.declaration.name)) {
|
|
23178
23200
|
settled.add(member.name.toLowerCase());
|
|
23179
23201
|
}
|
|
23180
23202
|
return settled;
|
|
@@ -23192,7 +23214,7 @@ function baseClauseRange(declaration, anchor) {
|
|
|
23192
23214
|
return baseClause.range;
|
|
23193
23215
|
}
|
|
23194
23216
|
function resolveInvokedConstructor(declaration, call, diagnostics) {
|
|
23195
|
-
const headerParameters = declaration
|
|
23217
|
+
const headerParameters = requiredConstructorParameters(declaration);
|
|
23196
23218
|
if (headerParameters !== void 0) {
|
|
23197
23219
|
if (call.argumentNames.length > 0) {
|
|
23198
23220
|
validateArgumentsAgainstParameters(
|
|
@@ -23228,7 +23250,7 @@ function resolveInvokedConstructor(declaration, call, diagnostics) {
|
|
|
23228
23250
|
const parameterless = declaration.constructors.some(
|
|
23229
23251
|
(constructor2) => parameterListIsFullyDefaulted(constructor2.parameters)
|
|
23230
23252
|
);
|
|
23231
|
-
if (parameterless || call.site
|
|
23253
|
+
if (parameterless || call.site !== "base") return parameterless;
|
|
23232
23254
|
diagnostics.push({
|
|
23233
23255
|
code: "base-requires-construction",
|
|
23234
23256
|
message: `The base call must pass arguments: '${declaration.name}' declares no parameterless constructor \u2014 candidates: ${describeConstructors(declaration)}.`,
|
|
@@ -23245,7 +23267,7 @@ function resolveInvokedConstructor(declaration, call, diagnostics) {
|
|
|
23245
23267
|
);
|
|
23246
23268
|
return true;
|
|
23247
23269
|
}
|
|
23248
|
-
if (call.site
|
|
23270
|
+
if (call.site !== "new") {
|
|
23249
23271
|
let positional = false;
|
|
23250
23272
|
call.argumentNames.forEach((name, index) => {
|
|
23251
23273
|
if (name !== null) return;
|
|
@@ -31690,7 +31712,7 @@ var init_registry = __esm({
|
|
|
31690
31712
|
"../packages/manifest/schema-contract/registry.mjs"() {
|
|
31691
31713
|
"use strict";
|
|
31692
31714
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
31693
|
-
cliVersion: "0.68.
|
|
31715
|
+
cliVersion: "0.68.4",
|
|
31694
31716
|
projectFileUploadBatchSize: 32,
|
|
31695
31717
|
documentRecords: {
|
|
31696
31718
|
member: {
|
|
@@ -79315,6 +79337,8 @@ function resolveBaseConstructorRecord(record6, ctx) {
|
|
|
79315
79337
|
);
|
|
79316
79338
|
if (resolution.kind === "resolved") return resolution.overload;
|
|
79317
79339
|
if (resolution.kind === "noMatch" && baseArguments.length === 0) {
|
|
79340
|
+
if (owningClass.requiredConstructorId === record6.id && evaluatorSchemaIndex(ctx).class(baseClassId)?.requiredConstructorId == null)
|
|
79341
|
+
return null;
|
|
79318
79342
|
throw new NSGetterRuntimeError(
|
|
79319
79343
|
`Constructor '${record6.id}' on '${owningClass.name}' must call ': base(...)': its base class declares constructors but none parameterless.`
|
|
79320
79344
|
);
|
|
@@ -88861,6 +88885,8 @@ function resolveBaseConstructorOverload(args, owner) {
|
|
|
88861
88885
|
);
|
|
88862
88886
|
if (resolution.kind === "resolved") return resolution.overload;
|
|
88863
88887
|
if (resolution.kind === "noMatch" && baseArguments.length === 0) {
|
|
88888
|
+
if (owner.requiredConstructorId === args.constructor.id && baseClass.requiredConstructorId == null)
|
|
88889
|
+
return null;
|
|
88864
88890
|
throw new Error(
|
|
88865
88891
|
`Constructor "${args.constructor.id}" must declare a base call: base class "${baseClass.name}" declares constructors but none parameterless \u2014 candidates: ${describeConstructorOverloads(candidates)}.`
|
|
88866
88892
|
);
|
|
@@ -165112,7 +165138,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
165112
165138
|
async function main() {
|
|
165113
165139
|
const args = parseArgs(process.argv.slice(2));
|
|
165114
165140
|
if (args.command === "--version") {
|
|
165115
|
-
console.log("0.68.
|
|
165141
|
+
console.log("0.68.4");
|
|
165116
165142
|
return;
|
|
165117
165143
|
}
|
|
165118
165144
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
package/dist/test-worker.mjs
CHANGED
|
@@ -22401,6 +22401,8 @@ function resolveBaseConstructorRecord(record3, ctx) {
|
|
|
22401
22401
|
);
|
|
22402
22402
|
if (resolution.kind === "resolved") return resolution.overload;
|
|
22403
22403
|
if (resolution.kind === "noMatch" && baseArguments.length === 0) {
|
|
22404
|
+
if (owningClass.requiredConstructorId === record3.id && evaluatorSchemaIndex(ctx).class(baseClassId)?.requiredConstructorId == null)
|
|
22405
|
+
return null;
|
|
22404
22406
|
throw new NSGetterRuntimeError(
|
|
22405
22407
|
`Constructor '${record3.id}' on '${owningClass.name}' must call ': base(...)': its base class declares constructors but none parameterless.`
|
|
22406
22408
|
);
|
package/package.json
CHANGED
|
@@ -110,7 +110,7 @@ wrappers.
|
|
|
110
110
|
The marker near the top of `SKILL.md` must exactly match the package version:
|
|
111
111
|
|
|
112
112
|
```html
|
|
113
|
-
<!-- reviewed-through-cli: 0.68.
|
|
113
|
+
<!-- reviewed-through-cli: 0.68.4 -->
|
|
114
114
|
```
|
|
115
115
|
|
|
116
116
|
The quoted version above is checked too, so this instruction cannot go stale
|
|
@@ -385,6 +385,14 @@ class Child(string name) : Base {
|
|
|
385
385
|
}
|
|
386
386
|
```
|
|
387
387
|
|
|
388
|
+
A header base clause with no arguments, such as `: Base()` or `: Base`,
|
|
389
|
+
runs a zero-argument or fully defaulted base constructor when available.
|
|
390
|
+
Otherwise, if the base has only declared constructors, it uses the member
|
|
391
|
+
initializers and base block without running a base constructor. The base block
|
|
392
|
+
must settle any remaining required members. A required base constructor cannot
|
|
393
|
+
be skipped. A declared constructor's `: base()` must call a base constructor
|
|
394
|
+
when the base declares one.
|
|
395
|
+
|
|
388
396
|
Bind generic base arguments explicitly when needed. Reject a subclass that
|
|
389
397
|
omits required base arguments or leaves any inherited required member
|
|
390
398
|
unsettled.
|