@neocompose/cli 0.75.1 → 0.75.2
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 +11 -0
- package/dist/neo.mjs +297 -79
- package/dist/test-worker.mjs +7 -1
- package/package.json +1 -1
- package/skills/neocompose-cli/SKILL.md +3 -2
- package/skills/neocompose-cli/references/cli-development.md +5 -2
- package/skills/neocompose-cli/references/declarations-and-construction.md +25 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.75.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 45f828c: Preserve generic constructor arguments and nested reference types when exporting member defaults, so Neowyn animation schemas compile without changing record identities.
|
|
8
|
+
- 60935a5: Report invalid object-initializer semicolons consistently in the editor and CLI, with the authored file position and a comma-separator hint.
|
|
9
|
+
- 869b95b: Ignore formatting-only changes in stored initializer recipes, computed member
|
|
10
|
+
defaults, and inline constructor delegates. Preserve their existing compiled
|
|
11
|
+
bodies while continuing to detect code and string-literal content edits.
|
|
12
|
+
- 267ccd2: Keep valid root value graphs available when another root construction fails, and show required-member declaration locations in CLI diagnostics.
|
|
13
|
+
|
|
3
14
|
## 0.75.1
|
|
4
15
|
|
|
5
16
|
### Patch Changes
|
package/dist/neo.mjs
CHANGED
|
@@ -18773,6 +18773,12 @@ var init_executable_parser = __esm({
|
|
|
18773
18773
|
value: this.parseExpr(),
|
|
18774
18774
|
pos: at(name)
|
|
18775
18775
|
});
|
|
18776
|
+
if (this.peek().text === ";") {
|
|
18777
|
+
throw new CompileError(
|
|
18778
|
+
"Object initializer assignments use commas, not semicolons. Replace ';' with ',' or omit it after the last assignment; the enclosing declaration still ends with ';'.",
|
|
18779
|
+
at(this.peek())
|
|
18780
|
+
);
|
|
18781
|
+
}
|
|
18776
18782
|
if (!this.eat("punctuation", ",")) break;
|
|
18777
18783
|
if (this.peek().kind === "punctuation" && this.peek().text === "}") break;
|
|
18778
18784
|
}
|
|
@@ -22534,8 +22540,13 @@ var init_source_diagnostics = __esm({
|
|
|
22534
22540
|
"neoflow-incomplete-draft"
|
|
22535
22541
|
]);
|
|
22536
22542
|
SchemaSourceError = class extends Error {
|
|
22537
|
-
constructor(detail, file, line, column, code, severity = "error", range2) {
|
|
22538
|
-
super(
|
|
22543
|
+
constructor(detail, file, line, column, code, severity = "error", range2, relatedInformation) {
|
|
22544
|
+
super(
|
|
22545
|
+
`${file}:${line}:${column} \u2014 ${detail}${relatedInformation?.map(
|
|
22546
|
+
({ location: location3, message }) => `
|
|
22547
|
+
${location3.uri}:${location3.range.start.line + 1}:${location3.range.start.character + 1} \u2014 ${message}`
|
|
22548
|
+
).join("") ?? ""}`
|
|
22549
|
+
);
|
|
22539
22550
|
this.detail = detail;
|
|
22540
22551
|
this.file = file;
|
|
22541
22552
|
this.line = line;
|
|
@@ -22543,6 +22554,7 @@ var init_source_diagnostics = __esm({
|
|
|
22543
22554
|
this.code = code;
|
|
22544
22555
|
this.severity = severity;
|
|
22545
22556
|
this.range = range2;
|
|
22557
|
+
this.relatedInformation = relatedInformation;
|
|
22546
22558
|
this.name = "SchemaSourceError";
|
|
22547
22559
|
}
|
|
22548
22560
|
detail;
|
|
@@ -22552,6 +22564,7 @@ var init_source_diagnostics = __esm({
|
|
|
22552
22564
|
code;
|
|
22553
22565
|
severity;
|
|
22554
22566
|
range;
|
|
22567
|
+
relatedInformation;
|
|
22555
22568
|
};
|
|
22556
22569
|
}
|
|
22557
22570
|
});
|
|
@@ -43398,7 +43411,11 @@ function validateDeclaration(uri, declaration, documentKind, environment, diagno
|
|
|
43398
43411
|
environment,
|
|
43399
43412
|
declaration.initializer.range,
|
|
43400
43413
|
diagnostics,
|
|
43401
|
-
anchorOf(declaration.initializer)
|
|
43414
|
+
anchorOf(declaration.initializer),
|
|
43415
|
+
DECLARATION_BODY_GLOBAL_TYPES.has(declaration.type.name) || isNeoVariantFamilyTypeName(declaration.type.name) ? void 0 : {
|
|
43416
|
+
code: "invalid-project-global-initializer",
|
|
43417
|
+
label: `Global '${declaration.name}' initializer`
|
|
43418
|
+
}
|
|
43402
43419
|
);
|
|
43403
43420
|
return;
|
|
43404
43421
|
}
|
|
@@ -43753,6 +43770,10 @@ function validateProjectRootGlobal(uri, declaration, environment, diagnostics) {
|
|
|
43753
43770
|
{
|
|
43754
43771
|
text: actual.initializer,
|
|
43755
43772
|
start: slotPosition(declaration.initializer.range.start, actual.start)
|
|
43773
|
+
},
|
|
43774
|
+
{
|
|
43775
|
+
code: "invalid-project-global-initializer",
|
|
43776
|
+
label: `Root '${expected.name}' initializer`
|
|
43756
43777
|
}
|
|
43757
43778
|
);
|
|
43758
43779
|
}
|
|
@@ -46105,7 +46126,7 @@ function classDerivesFromName(name, ancestorName, environment, seen = /* @__PURE
|
|
|
46105
46126
|
return classDerivesFromName(base.name, ancestorName, environment, seen);
|
|
46106
46127
|
});
|
|
46107
46128
|
}
|
|
46108
|
-
var NEO_VARIANT_FOLDER_SETTING, primitiveType, LIST_COLUMN_INHERITANCE_KEY, SEMANTIC_PRIMITIVE_TYPE_NAMES;
|
|
46129
|
+
var NEO_VARIANT_FOLDER_SETTING, primitiveType, LIST_COLUMN_INHERITANCE_KEY, DECLARATION_BODY_GLOBAL_TYPES, SEMANTIC_PRIMITIVE_TYPE_NAMES;
|
|
46109
46130
|
var init_project_source_semantics = __esm({
|
|
46110
46131
|
"../packages/neoscript-language/src/project-source-semantics.ts"() {
|
|
46111
46132
|
"use strict";
|
|
@@ -46129,6 +46150,12 @@ var init_project_source_semantics = __esm({
|
|
|
46129
46150
|
NEO_VARIANT_FOLDER_SETTING = "folder";
|
|
46130
46151
|
primitiveType = (name) => ({ name });
|
|
46131
46152
|
LIST_COLUMN_INHERITANCE_KEY = "__other__";
|
|
46153
|
+
DECLARATION_BODY_GLOBAL_TYPES = /* @__PURE__ */ new Set([
|
|
46154
|
+
NEOSCRIPT_IMAGE_REGISTRY_TYPE,
|
|
46155
|
+
NEOSCRIPT_AUDIO_CLIP_REGISTRY_TYPE,
|
|
46156
|
+
"NeoPriorityGroup",
|
|
46157
|
+
"NeoDialogueGroup"
|
|
46158
|
+
]);
|
|
46132
46159
|
SEMANTIC_PRIMITIVE_TYPE_NAMES = /* @__PURE__ */ new Set([
|
|
46133
46160
|
"bool",
|
|
46134
46161
|
"int",
|
|
@@ -51821,7 +51848,7 @@ var init_registry = __esm({
|
|
|
51821
51848
|
"../packages/manifest/schema-contract/registry.mjs"() {
|
|
51822
51849
|
"use strict";
|
|
51823
51850
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
51824
|
-
cliVersion: "0.75.
|
|
51851
|
+
cliVersion: "0.75.2",
|
|
51825
51852
|
projectFileUploadBatchSize: 32,
|
|
51826
51853
|
documentRecords: {
|
|
51827
51854
|
member: {
|
|
@@ -63657,6 +63684,7 @@ var init_variant_selection_source = __esm({
|
|
|
63657
63684
|
function emitProjectSourcesV4(manifest, options = {}) {
|
|
63658
63685
|
const context = {
|
|
63659
63686
|
manifest,
|
|
63687
|
+
classBindings: /* @__PURE__ */ new Map(),
|
|
63660
63688
|
classes: new Map(manifest.classes.map((entry) => [entry.id, entry])),
|
|
63661
63689
|
interfaces: new Map(manifest.interfaces.map((entry) => [entry.id, entry])),
|
|
63662
63690
|
enums: new Map(manifest.enums.map((entry) => [entry.id, entry])),
|
|
@@ -64373,7 +64401,6 @@ function renderEntryType(context, entryMemberId, label, enclosingClassId, elemen
|
|
|
64373
64401
|
}
|
|
64374
64402
|
function renderMemberType(context, member, enclosingClassId, elementSettings = false) {
|
|
64375
64403
|
const nullable2 = !member.required;
|
|
64376
|
-
const closedGenerics = enclosingClassId === void 0 ? void 0 : classGenericMemberBindings(context.classes, enclosingClassId);
|
|
64377
64404
|
let value;
|
|
64378
64405
|
switch (member.kind) {
|
|
64379
64406
|
case "null":
|
|
@@ -64441,11 +64468,11 @@ function renderMemberType(context, member, enclosingClassId, elementSettings = f
|
|
|
64441
64468
|
if (binding.kind === "member") {
|
|
64442
64469
|
boundMemberId = binding.memberId;
|
|
64443
64470
|
} else {
|
|
64444
|
-
|
|
64445
|
-
|
|
64446
|
-
|
|
64447
|
-
|
|
64448
|
-
|
|
64471
|
+
return renderGenericType(
|
|
64472
|
+
context,
|
|
64473
|
+
binding.genericParamId,
|
|
64474
|
+
enclosingClassId
|
|
64475
|
+
);
|
|
64449
64476
|
}
|
|
64450
64477
|
return renderMemberType(
|
|
64451
64478
|
context,
|
|
@@ -64478,7 +64505,11 @@ function renderMemberType(context, member, enclosingClassId, elementSettings = f
|
|
|
64478
64505
|
value = member.multiselect ? "Set<NeoDialogueReference>" : "NeoDialogueReference";
|
|
64479
64506
|
break;
|
|
64480
64507
|
case "generic":
|
|
64481
|
-
value =
|
|
64508
|
+
value = renderGenericType(
|
|
64509
|
+
context,
|
|
64510
|
+
member.genericParamId,
|
|
64511
|
+
enclosingClassId
|
|
64512
|
+
);
|
|
64482
64513
|
break;
|
|
64483
64514
|
case "computed":
|
|
64484
64515
|
value = renderType(context, member.returnType);
|
|
@@ -64705,7 +64736,71 @@ function dictionaryOptions(context, enumId) {
|
|
|
64705
64736
|
context.dictionaryKeyOptions.set(enumId, result);
|
|
64706
64737
|
return result;
|
|
64707
64738
|
}
|
|
64739
|
+
function cachedClassBindings(context, classId) {
|
|
64740
|
+
let bindings = context.classBindings.get(classId);
|
|
64741
|
+
if (bindings === void 0) {
|
|
64742
|
+
bindings = classGenericBindings(context.classes, classId);
|
|
64743
|
+
context.classBindings.set(classId, bindings);
|
|
64744
|
+
}
|
|
64745
|
+
return bindings;
|
|
64746
|
+
}
|
|
64747
|
+
function renderGenericType(context, parameterId, enclosingClassId) {
|
|
64748
|
+
const bindings = context.genericBindings ?? (enclosingClassId === void 0 ? void 0 : cachedClassBindings(context, enclosingClassId));
|
|
64749
|
+
const binding = resolveGenericBinding(parameterId, bindings);
|
|
64750
|
+
return binding.kind === "member" ? renderMemberType(
|
|
64751
|
+
context,
|
|
64752
|
+
required(context.members, binding.memberId, "generic binding"),
|
|
64753
|
+
enclosingClassId
|
|
64754
|
+
) : genericName(context, binding.genericParamId);
|
|
64755
|
+
}
|
|
64756
|
+
function resolveGenericBinding(parameterId, bindings) {
|
|
64757
|
+
const visited = /* @__PURE__ */ new Set();
|
|
64758
|
+
let cursor = parameterId;
|
|
64759
|
+
while (!visited.has(cursor)) {
|
|
64760
|
+
visited.add(cursor);
|
|
64761
|
+
const binding = bindings?.get(cursor);
|
|
64762
|
+
if (binding === void 0) break;
|
|
64763
|
+
if (binding.kind === "member") return binding;
|
|
64764
|
+
cursor = binding.genericParamId;
|
|
64765
|
+
}
|
|
64766
|
+
return { kind: "generic", genericParamId: cursor };
|
|
64767
|
+
}
|
|
64768
|
+
function constructionContext(context, member, enclosingClassId) {
|
|
64769
|
+
const outer = context.genericBindings ?? (enclosingClassId === void 0 ? void 0 : cachedClassBindings(context, enclosingClassId));
|
|
64770
|
+
const inherited = cachedClassBindings(context, member.classId);
|
|
64771
|
+
const arguments_ = Object.entries(member.classArguments);
|
|
64772
|
+
if (inherited.size === 0 && arguments_.length === 0) return context;
|
|
64773
|
+
const bindings = new Map(outer);
|
|
64774
|
+
for (const [parameter4, binding] of inherited)
|
|
64775
|
+
bindings.set(parameter4, binding);
|
|
64776
|
+
for (const [parameter4, binding] of arguments_) {
|
|
64777
|
+
bindings.set(
|
|
64778
|
+
parameter4,
|
|
64779
|
+
binding.kind === "generic" ? resolveGenericBinding(binding.genericParamId, outer) : binding
|
|
64780
|
+
);
|
|
64781
|
+
}
|
|
64782
|
+
return { ...context, genericBindings: bindings };
|
|
64783
|
+
}
|
|
64708
64784
|
function renderDefaultValue(context, member, wrapper, enclosingClassId) {
|
|
64785
|
+
if (member.kind === "generic" && context.genericBindings) {
|
|
64786
|
+
const bindingId = terminalGenericBindingMemberId(
|
|
64787
|
+
member.genericParamId,
|
|
64788
|
+
context.genericBindings
|
|
64789
|
+
);
|
|
64790
|
+
if (bindingId !== void 0) {
|
|
64791
|
+
const binding = required(
|
|
64792
|
+
context.members,
|
|
64793
|
+
bindingId,
|
|
64794
|
+
"generic default binding"
|
|
64795
|
+
);
|
|
64796
|
+
const positioned = structuredLeafPartialChild(
|
|
64797
|
+
member.partial === true,
|
|
64798
|
+
binding
|
|
64799
|
+
);
|
|
64800
|
+
const resolved = positioned.kind === "class" && member.partial === true ? { ...positioned, partial: true } : positioned;
|
|
64801
|
+
return renderDefaultValue(context, resolved, wrapper, enclosingClassId);
|
|
64802
|
+
}
|
|
64803
|
+
}
|
|
64709
64804
|
const value = wrapper.value;
|
|
64710
64805
|
if (value === null) return "null";
|
|
64711
64806
|
if (member.kind === "decimal" && typeof value === "string") return value;
|
|
@@ -64741,16 +64836,21 @@ function renderDefaultValue(context, member, wrapper, enclosingClassId) {
|
|
|
64741
64836
|
}
|
|
64742
64837
|
if (member.kind === "class" && isObject3(value)) {
|
|
64743
64838
|
const target = required(context.classes, member.classId, "class");
|
|
64839
|
+
const nestedContext = constructionContext(
|
|
64840
|
+
context,
|
|
64841
|
+
member,
|
|
64842
|
+
enclosingClassId
|
|
64843
|
+
);
|
|
64744
64844
|
const assignments = Object.entries(value).map(([key, item]) => {
|
|
64745
64845
|
const childId = target.schema[key];
|
|
64746
64846
|
const child2 = childId ? context.members.get(childId) : void 0;
|
|
64747
64847
|
const positioned = child2 ? structuredLeafPartialChild(member.partial === true, child2) : void 0;
|
|
64748
|
-
return `${key} = ${positioned ? renderNestedValue(
|
|
64848
|
+
return `${key} = ${positioned ? renderNestedValue(nestedContext, positioned, item, enclosingClassId) : jsonValue2(item)}`;
|
|
64749
64849
|
});
|
|
64750
64850
|
if (member.partial === true) {
|
|
64751
64851
|
return `new { ${assignments.join(", ")} }`;
|
|
64752
64852
|
}
|
|
64753
|
-
return `new ${
|
|
64853
|
+
return `new ${renderMemberType(context, member, enclosingClassId).replace(/\?$/u, "")}${assignments.length ? ` { ${assignments.join(", ")} }` : "()"}`;
|
|
64754
64854
|
}
|
|
64755
64855
|
if (member.kind === "action") {
|
|
64756
64856
|
return renderActionListeners(context, member, value);
|
|
@@ -66138,45 +66238,30 @@ function commentEndIndex(source, index) {
|
|
|
66138
66238
|
return null;
|
|
66139
66239
|
}
|
|
66140
66240
|
function stripInitializerComments(source) {
|
|
66141
|
-
const
|
|
66142
|
-
|
|
66143
|
-
|
|
66144
|
-
|
|
66145
|
-
for (
|
|
66146
|
-
|
|
66147
|
-
|
|
66148
|
-
|
|
66149
|
-
|
|
66150
|
-
|
|
66151
|
-
|
|
66152
|
-
}
|
|
66153
|
-
const afterComment = commentEndIndex(source, index);
|
|
66154
|
-
if (afterComment !== null) {
|
|
66155
|
-
const line = lines[lines.length - 1];
|
|
66156
|
-
if (segmentStart < index) {
|
|
66157
|
-
line.parts.push(source.slice(segmentStart, index));
|
|
66158
|
-
}
|
|
66159
|
-
line.removedComment = true;
|
|
66160
|
-
specialCharacters.lastIndex = afterComment;
|
|
66161
|
-
segmentStart = afterComment;
|
|
66162
|
-
continue;
|
|
66163
|
-
}
|
|
66164
|
-
if (character === "\n") {
|
|
66165
|
-
if (segmentStart < index) {
|
|
66166
|
-
lines[lines.length - 1].parts.push(source.slice(segmentStart, index));
|
|
66167
|
-
}
|
|
66168
|
-
lines.push({ parts: [], removedComment: false });
|
|
66169
|
-
segmentStart = index + 1;
|
|
66170
|
-
continue;
|
|
66241
|
+
const lexed = lex(source);
|
|
66242
|
+
const commentLines = /* @__PURE__ */ new Set();
|
|
66243
|
+
const parts = [];
|
|
66244
|
+
let cursor = 0;
|
|
66245
|
+
for (const token of lexed.tokens) {
|
|
66246
|
+
if (token.kind !== "comment") continue;
|
|
66247
|
+
parts.push(source.slice(cursor, token.start));
|
|
66248
|
+
parts.push(token.raw.replace(/[^\r\n]/g, ""));
|
|
66249
|
+
cursor = token.end;
|
|
66250
|
+
for (let line = token.range.start.line; line <= token.range.end.line; line++) {
|
|
66251
|
+
commentLines.add(line);
|
|
66171
66252
|
}
|
|
66172
|
-
if (character === '"' || character === "'") quote6 = character;
|
|
66173
66253
|
}
|
|
66174
|
-
|
|
66175
|
-
|
|
66254
|
+
parts.push(source.slice(cursor));
|
|
66255
|
+
const literalNewlines = /* @__PURE__ */ new Set();
|
|
66256
|
+
for (const token of lexed.roots) {
|
|
66257
|
+
if (token.kind !== "string") continue;
|
|
66258
|
+
for (let line = token.range.start.line; line < token.range.end.line; line++) {
|
|
66259
|
+
literalNewlines.add(line);
|
|
66260
|
+
}
|
|
66176
66261
|
}
|
|
66177
|
-
return
|
|
66178
|
-
text:
|
|
66179
|
-
removedComment:
|
|
66262
|
+
return parts.join("").split("\n").map((line, index) => ({
|
|
66263
|
+
text: literalNewlines.has(index) ? line : line.trimEnd(),
|
|
66264
|
+
removedComment: commentLines.has(index)
|
|
66180
66265
|
})).filter((line) => !line.removedComment || line.text.trim().length > 0).map((line) => line.text).join("\n").trim();
|
|
66181
66266
|
}
|
|
66182
66267
|
function normalizeBodySource(source) {
|
|
@@ -66222,7 +66307,8 @@ function normalizeInitializerSourceUncached(source) {
|
|
|
66222
66307
|
const stripped = stripInitializerComments(source);
|
|
66223
66308
|
const lines = stripped.split("\n");
|
|
66224
66309
|
if (lines.length < 2) return stripped;
|
|
66225
|
-
const
|
|
66310
|
+
const literalLines = neoScriptLiteralContinuationLines(stripped);
|
|
66311
|
+
const continuations = lines.slice(1).filter((line, index) => !literalLines.has(index + 1) && line.length > 0);
|
|
66226
66312
|
if (continuations.length === 0) return stripped;
|
|
66227
66313
|
const common = Math.min(
|
|
66228
66314
|
...continuations.map((line) => line.length - line.trimStart().length)
|
|
@@ -66230,7 +66316,9 @@ function normalizeInitializerSourceUncached(source) {
|
|
|
66230
66316
|
if (common === 0) return stripped;
|
|
66231
66317
|
return [
|
|
66232
66318
|
lines[0],
|
|
66233
|
-
...lines.slice(1).map(
|
|
66319
|
+
...lines.slice(1).map(
|
|
66320
|
+
(line, index) => literalLines.has(index + 1) || line.length === 0 ? line : line.slice(common)
|
|
66321
|
+
)
|
|
66234
66322
|
].join("\n");
|
|
66235
66323
|
}
|
|
66236
66324
|
function constructorExpressionSlice(source) {
|
|
@@ -66362,7 +66450,10 @@ function matchesStoredInitializer(defaultValue, source) {
|
|
|
66362
66450
|
if (!isObjectRecord2(defaultValue) || !isObjectRecord2(defaultValue.init))
|
|
66363
66451
|
return false;
|
|
66364
66452
|
const code = defaultValue.init.code;
|
|
66365
|
-
return typeof code === "string" &&
|
|
66453
|
+
return typeof code === "string" && sameNeoScriptTokens(
|
|
66454
|
+
normalizeInitializerSource(code),
|
|
66455
|
+
normalizeInitializerSource(source)
|
|
66456
|
+
);
|
|
66366
66457
|
}
|
|
66367
66458
|
var normalizedInitializers, normalizedInitializerCharacters, MAX_NORMALIZED_INITIALIZER_CHARACTERS;
|
|
66368
66459
|
var init_init_source = __esm({
|
|
@@ -126720,7 +126811,8 @@ function mergedOverStoredRow(base, lowered) {
|
|
|
126720
126811
|
if ("action" in argument2) continue;
|
|
126721
126812
|
const stored = storedArgs[key];
|
|
126722
126813
|
if (!isObjectRecord2(stored)) continue;
|
|
126723
|
-
if (stored.code !==
|
|
126814
|
+
if (typeof stored.code !== "string") continue;
|
|
126815
|
+
if (!sameNeoScriptTokens(stored.code, argument2.code)) continue;
|
|
126724
126816
|
if (!("action" in stored)) continue;
|
|
126725
126817
|
preserved ??= { ...loweredArgs };
|
|
126726
126818
|
preserved[key] = stored;
|
|
@@ -127065,6 +127157,27 @@ function drainValueReferenceObligationsV4(state, manifest, options) {
|
|
|
127065
127157
|
...collectionValueObligations(manifest),
|
|
127066
127158
|
...options.registry.referenceObligations
|
|
127067
127159
|
]) {
|
|
127160
|
+
if (obligation.kind === "reference" && options.unavailableReferenceMemberIds?.has(obligation.memberId))
|
|
127161
|
+
continue;
|
|
127162
|
+
if (options.unavailableValueIds?.size) {
|
|
127163
|
+
let targetId;
|
|
127164
|
+
switch (obligation.kind) {
|
|
127165
|
+
case "collectionValue":
|
|
127166
|
+
targetId = obligation.collectionValueId;
|
|
127167
|
+
break;
|
|
127168
|
+
case "constructorProjection":
|
|
127169
|
+
targetId = obligation.targetId;
|
|
127170
|
+
break;
|
|
127171
|
+
case "reference":
|
|
127172
|
+
if (obligation.target.spelling === "id")
|
|
127173
|
+
targetId = obligation.target.id;
|
|
127174
|
+
else if (obligation.target.spelling === "symbol")
|
|
127175
|
+
targetId = obligation.target.resolved.id;
|
|
127176
|
+
break;
|
|
127177
|
+
}
|
|
127178
|
+
if (targetId !== void 0 && options.unavailableValueIds.has(targetId))
|
|
127179
|
+
continue;
|
|
127180
|
+
}
|
|
127068
127181
|
const failure = settleReferenceObligation(
|
|
127069
127182
|
context,
|
|
127070
127183
|
obligation,
|
|
@@ -131707,6 +131820,10 @@ function annotationId2(annotations) {
|
|
|
131707
131820
|
}
|
|
131708
131821
|
function addReconstructed(context, recordKind, recordId, fileFields, source, options = {}) {
|
|
131709
131822
|
const key = `${recordKind}:${recordId}`;
|
|
131823
|
+
const base = context.state[key]?.data;
|
|
131824
|
+
if (recordKind === "value" && isObjectRecord2(base) && isObjectRecord2(fileFields.init) && typeof fileFields.init.code === "string" && matchesStoredInitializer(base, fileFields.init.code)) {
|
|
131825
|
+
fileFields = { ...fileFields, init: base.init };
|
|
131826
|
+
}
|
|
131710
131827
|
const existing = context.reconstructed.get(key);
|
|
131711
131828
|
const line = source.range.start.line + 1;
|
|
131712
131829
|
if (existing !== void 0) {
|
|
@@ -134006,6 +134123,7 @@ var INFERRED_GENERIC_CLASS_PREFIX, MEMBER_KIND_DICTIONARY2, MEMBER_KIND_LIST2, M
|
|
|
134006
134123
|
var init_value_sources = __esm({
|
|
134007
134124
|
"src/project-source/value-sources.ts"() {
|
|
134008
134125
|
"use strict";
|
|
134126
|
+
init_lexer();
|
|
134009
134127
|
init_codecs();
|
|
134010
134128
|
init_reference_target_types();
|
|
134011
134129
|
init_listener_template_graph();
|
|
@@ -136920,26 +137038,94 @@ ${declarations.join("\n\n")}
|
|
|
136920
137038
|
}
|
|
136921
137039
|
function lowerProjectRootSourceV4(state, analysis, manifest, options = {}) {
|
|
136922
137040
|
const registry = options.registry ?? createValueLowerRegistryV4();
|
|
137041
|
+
const unavailableSlots = /* @__PURE__ */ new Set();
|
|
137042
|
+
const unavailableValueIds = /* @__PURE__ */ new Set();
|
|
136923
137043
|
const validated = validateProjectRootEnvelopeV4(
|
|
136924
137044
|
state,
|
|
136925
137045
|
analysis,
|
|
136926
137046
|
registry.parsedInitializers
|
|
136927
137047
|
);
|
|
136928
137048
|
if (validated === null) {
|
|
136929
|
-
return {
|
|
137049
|
+
return {
|
|
137050
|
+
records: [],
|
|
137051
|
+
memberValueIds: /* @__PURE__ */ new Map(),
|
|
137052
|
+
seeds: /* @__PURE__ */ new Map(),
|
|
137053
|
+
unavailableSlots,
|
|
137054
|
+
unavailableValueIds
|
|
137055
|
+
};
|
|
136930
137056
|
}
|
|
136931
137057
|
const { expected, global, slots } = validated;
|
|
136932
|
-
const
|
|
136933
|
-
|
|
136934
|
-
|
|
136935
|
-
|
|
136936
|
-
|
|
136937
|
-
|
|
136938
|
-
|
|
136939
|
-
|
|
136940
|
-
|
|
136941
|
-
|
|
137058
|
+
const initializerStart = global.initializerSource?.range.start;
|
|
137059
|
+
const errors = analysis.diagnostics.filter(
|
|
137060
|
+
(diagnostic) => diagnostic.severity === "error" && diagnostic.uri === global.source.uri
|
|
137061
|
+
);
|
|
137062
|
+
const bindings = expected.flatMap((root, index) => {
|
|
137063
|
+
const slot = slots[index];
|
|
137064
|
+
if (errors.length > 0 && initializerStart !== void 0) {
|
|
137065
|
+
const line = initializerStart.line + slot.start.line - 1;
|
|
137066
|
+
const character = slot.start.column - 1 + (slot.start.line === 1 ? initializerStart.character : 0);
|
|
137067
|
+
const lines = slot.initializer.split("\n");
|
|
137068
|
+
const endLine = line + lines.length - 1;
|
|
137069
|
+
const endCharacter = lines.length === 1 ? character + slot.initializer.length : lines[lines.length - 1].length;
|
|
137070
|
+
if (errors.some(
|
|
137071
|
+
({ range: { start } }) => (start.line > line || start.line === line && start.character >= character) && (start.line < endLine || start.line === endLine && start.character < endCharacter)
|
|
137072
|
+
)) {
|
|
137073
|
+
unavailableSlots.add(slot.name);
|
|
137074
|
+
collectAuthoredValueIds(
|
|
137075
|
+
parseCachedInitializer(registry.parsedInitializers, slot.initializer),
|
|
137076
|
+
unavailableValueIds
|
|
137077
|
+
);
|
|
137078
|
+
return [];
|
|
137079
|
+
}
|
|
137080
|
+
} else if (errors.length > 0) {
|
|
137081
|
+
unavailableSlots.add(slot.name);
|
|
137082
|
+
collectAuthoredValueIds(
|
|
137083
|
+
parseCachedInitializer(registry.parsedInitializers, slot.initializer),
|
|
137084
|
+
unavailableValueIds
|
|
137085
|
+
);
|
|
137086
|
+
return [];
|
|
137087
|
+
}
|
|
137088
|
+
return [
|
|
137089
|
+
{
|
|
137090
|
+
memberId: root.memberId,
|
|
137091
|
+
purpose: "stored",
|
|
137092
|
+
initializer: slots[index].initializer,
|
|
137093
|
+
source: global.source,
|
|
137094
|
+
label: `root.${root.slot.name}`
|
|
137095
|
+
}
|
|
137096
|
+
];
|
|
136942
137097
|
});
|
|
137098
|
+
return {
|
|
137099
|
+
...lowerStoredValueBindingsV4(state, manifest, bindings, {
|
|
137100
|
+
analysis,
|
|
137101
|
+
registry
|
|
137102
|
+
}),
|
|
137103
|
+
unavailableSlots,
|
|
137104
|
+
unavailableValueIds
|
|
137105
|
+
};
|
|
137106
|
+
}
|
|
137107
|
+
function collectAuthoredValueIds(expression, ids) {
|
|
137108
|
+
const pending = [expression];
|
|
137109
|
+
while (pending.length > 0) {
|
|
137110
|
+
const node = pending.pop();
|
|
137111
|
+
if (Array.isArray(node)) {
|
|
137112
|
+
for (const entry of node) pending.push(entry);
|
|
137113
|
+
continue;
|
|
137114
|
+
}
|
|
137115
|
+
if (!isObjectRecord2(node)) continue;
|
|
137116
|
+
if (node.kind === "annotated" && Array.isArray(node.annotations)) {
|
|
137117
|
+
for (const annotation2 of node.annotations) {
|
|
137118
|
+
if (!isObjectRecord2(annotation2) || annotation2.name !== "id" || !Array.isArray(annotation2.args))
|
|
137119
|
+
continue;
|
|
137120
|
+
const argument2 = annotation2.args[0];
|
|
137121
|
+
if (isObjectRecord2(argument2) && argument2.kind === "litString" && typeof argument2.value === "string")
|
|
137122
|
+
ids.add(argument2.value);
|
|
137123
|
+
}
|
|
137124
|
+
}
|
|
137125
|
+
for (const [key, value] of Object.entries(node)) {
|
|
137126
|
+
if (key !== "pos" && key !== "range") pending.push(value);
|
|
137127
|
+
}
|
|
137128
|
+
}
|
|
136943
137129
|
}
|
|
136944
137130
|
function validateProjectRootEnvelopeV4(state, analysis, parsedInitializers) {
|
|
136945
137131
|
const project = Object.values(state).find(
|
|
@@ -137048,7 +137234,8 @@ function resolveRootPathCollectionValuesV4(args) {
|
|
|
137048
137234
|
placements,
|
|
137049
137235
|
rootValues,
|
|
137050
137236
|
fail2,
|
|
137051
|
-
args.resolveVirtualPath
|
|
137237
|
+
args.resolveVirtualPath,
|
|
137238
|
+
args.unavailableSlots
|
|
137052
137239
|
);
|
|
137053
137240
|
if (target !== null) resolved.set(member.id, target);
|
|
137054
137241
|
}
|
|
@@ -137087,7 +137274,8 @@ function resolveRootPathVariantFolderCollectionValuesV4(args) {
|
|
|
137087
137274
|
placements,
|
|
137088
137275
|
rootValues,
|
|
137089
137276
|
fail2,
|
|
137090
|
-
args.resolveVirtualPath
|
|
137277
|
+
args.resolveVirtualPath,
|
|
137278
|
+
args.unavailableSlots
|
|
137091
137279
|
);
|
|
137092
137280
|
if (target !== null) resolved.set(folder.id, target);
|
|
137093
137281
|
}
|
|
@@ -137125,7 +137313,8 @@ function resolveRootPathDialogueGroupCollectionValuesV4(args) {
|
|
|
137125
137313
|
label: String(record7.fileFields.name)
|
|
137126
137314
|
}
|
|
137127
137315
|
}),
|
|
137128
|
-
args.resolveVirtualPath
|
|
137316
|
+
args.resolveVirtualPath,
|
|
137317
|
+
args.unavailableSlots
|
|
137129
137318
|
);
|
|
137130
137319
|
if (target !== null) record7.fileFields.collectionValueId = target;
|
|
137131
137320
|
}
|
|
@@ -137143,7 +137332,7 @@ function rootSlotValueIds(state) {
|
|
|
137143
137332
|
}
|
|
137144
137333
|
return values;
|
|
137145
137334
|
}
|
|
137146
|
-
function walkRootValuePath(path, state, registry, placements, rootValues, fail2, resolveVirtualPath) {
|
|
137335
|
+
function walkRootValuePath(path, state, registry, placements, rootValues, fail2, resolveVirtualPath, unavailableSlots) {
|
|
137147
137336
|
const segments = path.split(".");
|
|
137148
137337
|
const slotName = segments[1];
|
|
137149
137338
|
if (segments[0] !== "root" || slotName === void 0) {
|
|
@@ -137152,6 +137341,7 @@ function walkRootValuePath(path, state, registry, placements, rootValues, fail2,
|
|
|
137152
137341
|
);
|
|
137153
137342
|
return null;
|
|
137154
137343
|
}
|
|
137344
|
+
if (unavailableSlots?.has(slotName)) return null;
|
|
137155
137345
|
const slotIndex = PROJECT_ROOT_SOURCE_SLOTS.findIndex(
|
|
137156
137346
|
(slot) => slot.name === slotName
|
|
137157
137347
|
);
|
|
@@ -140890,24 +141080,25 @@ function computeStatus(workspace, options, conflictedFiles, parseErrors, parseWa
|
|
|
140890
141080
|
diagnostic2.range.start.character + 1,
|
|
140891
141081
|
diagnostic2.code,
|
|
140892
141082
|
diagnostic2.severity,
|
|
140893
|
-
diagnostic2.range
|
|
141083
|
+
diagnostic2.range,
|
|
141084
|
+
diagnostic2.relatedInformation
|
|
140894
141085
|
);
|
|
140895
141086
|
if (positioned.severity === "error") parseErrors.push(positioned);
|
|
140896
141087
|
else parseWarnings.push(positioned);
|
|
140897
141088
|
}
|
|
140898
141089
|
if (analysis.diagnostics.some(
|
|
140899
|
-
(diagnostic2) => diagnostic2.code === "duplicate-project-id"
|
|
141090
|
+
(diagnostic2) => diagnostic2.severity === "error" && (diagnostic2.code === "duplicate-project-id" || diagnostic2.code === "invalid-project-global-initializer")
|
|
140900
141091
|
)) {
|
|
140901
141092
|
return refusedStatus(conflictedFiles, parseErrors, parseWarnings);
|
|
140902
141093
|
}
|
|
140903
141094
|
const rootDeclaration = analysis.configuration.globals.find(
|
|
140904
141095
|
(global) => global.type.name === "Root"
|
|
140905
141096
|
);
|
|
140906
|
-
const
|
|
140907
|
-
(error) => error.severity === "error" && error.uri === rootDeclaration.source.uri && sourceRangeContains(rootDeclaration.source.range, error.range.start)
|
|
141097
|
+
const rootHasEnvelopeError = rootDeclaration !== void 0 && analysis.diagnostics.some(
|
|
141098
|
+
(error) => error.severity === "error" && (error.code === "invalid-root-envelope" || error.code === "protected-root-envelope") && error.uri === rootDeclaration.source.uri && sourceRangeContains(rootDeclaration.source.range, error.range.start)
|
|
140908
141099
|
);
|
|
140909
141100
|
try {
|
|
140910
|
-
if (!
|
|
141101
|
+
if (!rootHasEnvelopeError) {
|
|
140911
141102
|
validateProjectRootEnvelopeV4(
|
|
140912
141103
|
loweringRecords,
|
|
140913
141104
|
analysis,
|
|
@@ -140940,7 +141131,7 @@ function computeStatus(workspace, options, conflictedFiles, parseErrors, parseWa
|
|
|
140940
141131
|
...analysis,
|
|
140941
141132
|
configuration: {
|
|
140942
141133
|
globals: analysis.configuration.globals.filter(
|
|
140943
|
-
(global) => global.type.name !== "Root" || rootEnvelopeValid && !
|
|
141134
|
+
(global) => global.type.name !== "Root" || rootEnvelopeValid && !rootHasEnvelopeError
|
|
140944
141135
|
)
|
|
140945
141136
|
},
|
|
140946
141137
|
schema: {
|
|
@@ -141143,8 +141334,28 @@ function computeStatus(workspace, options, conflictedFiles, parseErrors, parseWa
|
|
|
141143
141334
|
}) : {
|
|
141144
141335
|
records: [],
|
|
141145
141336
|
memberValueIds: /* @__PURE__ */ new Map(),
|
|
141146
|
-
seeds: /* @__PURE__ */ new Map()
|
|
141147
|
-
|
|
141337
|
+
seeds: /* @__PURE__ */ new Map(),
|
|
141338
|
+
unavailableSlots: new Set(
|
|
141339
|
+
PROJECT_ROOT_SOURCE_SLOTS.map((slot) => slot.name)
|
|
141340
|
+
),
|
|
141341
|
+
unavailableValueIds: /* @__PURE__ */ new Set()
|
|
141342
|
+
};
|
|
141343
|
+
const unavailableReferenceMemberIds = /* @__PURE__ */ new Set();
|
|
141344
|
+
if (rootValues.unavailableSlots.size > 0) {
|
|
141345
|
+
for (const member of manifest.members) {
|
|
141346
|
+
if (member.kind !== "lookup") continue;
|
|
141347
|
+
const spelled = member.collectionValueId;
|
|
141348
|
+
if (typeof spelled !== "string" || !spelled.startsWith("__pending__:root-path:") && !rootValues.unavailableValueIds.has(spelled))
|
|
141349
|
+
continue;
|
|
141350
|
+
if (rootValues.unavailableValueIds.has(spelled)) {
|
|
141351
|
+
unavailableReferenceMemberIds.add(member.id);
|
|
141352
|
+
continue;
|
|
141353
|
+
}
|
|
141354
|
+
const slot = spelled.slice("__pending__:root-path:".length).split(".")[1];
|
|
141355
|
+
if (slot !== void 0 && rootValues.unavailableSlots.has(slot))
|
|
141356
|
+
unavailableReferenceMemberIds.add(member.id);
|
|
141357
|
+
}
|
|
141358
|
+
}
|
|
141148
141359
|
reportPhase("documents-static-root", "Reading variants and dialogues\u2026");
|
|
141149
141360
|
authoredValueSeeds = new Map([...authoredValueSeeds, ...rootValues.seeds]);
|
|
141150
141361
|
const rootPathResolutionState = overlayProspectiveSourceRecords(
|
|
@@ -141182,6 +141393,7 @@ function computeStatus(workspace, options, conflictedFiles, parseErrors, parseWa
|
|
|
141182
141393
|
manifest,
|
|
141183
141394
|
state: rootPathResolutionState,
|
|
141184
141395
|
resolveVirtualPath,
|
|
141396
|
+
unavailableSlots: rootValues.unavailableSlots,
|
|
141185
141397
|
registry: valueLowerRegistry,
|
|
141186
141398
|
siteForMember: (memberId) => {
|
|
141187
141399
|
const span2 = sourceByKey.get(recordStateKey("member", memberId))?.span;
|
|
@@ -141211,6 +141423,7 @@ function computeStatus(workspace, options, conflictedFiles, parseErrors, parseWa
|
|
|
141211
141423
|
manifest,
|
|
141212
141424
|
state: rootPathResolutionState,
|
|
141213
141425
|
resolveVirtualPath,
|
|
141426
|
+
unavailableSlots: rootValues.unavailableSlots,
|
|
141214
141427
|
registry: valueLowerRegistry,
|
|
141215
141428
|
siteForFolder: (folderId) => {
|
|
141216
141429
|
const span2 = sourceByKey.get(
|
|
@@ -141324,6 +141537,7 @@ function computeStatus(workspace, options, conflictedFiles, parseErrors, parseWa
|
|
|
141324
141537
|
manifest,
|
|
141325
141538
|
state: rootPathResolutionState,
|
|
141326
141539
|
resolveVirtualPath,
|
|
141540
|
+
unavailableSlots: rootValues.unavailableSlots,
|
|
141327
141541
|
registry: valueLowerRegistry
|
|
141328
141542
|
});
|
|
141329
141543
|
if (collectionBindings !== void 0) {
|
|
@@ -141527,6 +141741,8 @@ function computeStatus(workspace, options, conflictedFiles, parseErrors, parseWa
|
|
|
141527
141741
|
registry: valueLowerRegistry,
|
|
141528
141742
|
analysis: projectAnalysisV4,
|
|
141529
141743
|
deletedValueIds,
|
|
141744
|
+
unavailableReferenceMemberIds,
|
|
141745
|
+
unavailableValueIds: rootValues.unavailableValueIds,
|
|
141530
141746
|
sourceTextByUri
|
|
141531
141747
|
}
|
|
141532
141748
|
);
|
|
@@ -142991,6 +143207,7 @@ var ANIMATION_DOCUMENT_RECORD_KINDS, ANIMATION_REPLAY_RECORD_KINDS, PROSPECTIVE_
|
|
|
142991
143207
|
var init_workspace_status_core = __esm({
|
|
142992
143208
|
"src/project-source/workspace-status-core.ts"() {
|
|
142993
143209
|
"use strict";
|
|
143210
|
+
init_project_root();
|
|
142994
143211
|
init_source_text();
|
|
142995
143212
|
init_runtime_diagnostic();
|
|
142996
143213
|
init_NSGetterRuntimeError();
|
|
@@ -145862,7 +146079,8 @@ function projectStatusJsonV4(status, options) {
|
|
|
145862
146079
|
code: error.code ?? null,
|
|
145863
146080
|
severity: error.severity,
|
|
145864
146081
|
blocking: isBlockingSchemaSourceError(error),
|
|
145865
|
-
message: error.message
|
|
146082
|
+
message: error.message,
|
|
146083
|
+
...error.relatedInformation?.length ? { relatedInformation: error.relatedInformation } : {}
|
|
145866
146084
|
})
|
|
145867
146085
|
),
|
|
145868
146086
|
records: status.changes.map(
|
|
@@ -192010,7 +192228,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
192010
192228
|
async function main() {
|
|
192011
192229
|
const args = parseArgs(process.argv.slice(2));
|
|
192012
192230
|
if (args.command === "--version") {
|
|
192013
|
-
console.log("0.75.
|
|
192231
|
+
console.log("0.75.2");
|
|
192014
192232
|
return;
|
|
192015
192233
|
}
|
|
192016
192234
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
package/dist/test-worker.mjs
CHANGED
|
@@ -29803,6 +29803,12 @@ var Parser = class _Parser {
|
|
|
29803
29803
|
value: this.parseExpr(),
|
|
29804
29804
|
pos: at(name)
|
|
29805
29805
|
});
|
|
29806
|
+
if (this.peek().text === ";") {
|
|
29807
|
+
throw new CompileError(
|
|
29808
|
+
"Object initializer assignments use commas, not semicolons. Replace ';' with ',' or omit it after the last assignment; the enclosing declaration still ends with ';'.",
|
|
29809
|
+
at(this.peek())
|
|
29810
|
+
);
|
|
29811
|
+
}
|
|
29806
29812
|
if (!this.eat("punctuation", ",")) break;
|
|
29807
29813
|
if (this.peek().kind === "punctuation" && this.peek().text === "}") break;
|
|
29808
29814
|
}
|
|
@@ -55714,7 +55720,7 @@ var SPECIALIZED_RELATION_KINDS = /* @__PURE__ */ new Set([
|
|
|
55714
55720
|
|
|
55715
55721
|
// ../packages/manifest/schema-contract/registry.mjs
|
|
55716
55722
|
var PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
55717
|
-
cliVersion: "0.75.
|
|
55723
|
+
cliVersion: "0.75.2",
|
|
55718
55724
|
projectFileUploadBatchSize: 32,
|
|
55719
55725
|
documentRecords: {
|
|
55720
55726
|
member: {
|
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.75.
|
|
12
|
+
<!-- reviewed-through-cli: 0.75.2 -->
|
|
13
13
|
|
|
14
14
|
# Neo Compose CLI
|
|
15
15
|
|
|
@@ -308,5 +308,6 @@ and `insert_final_newline` there to keep regenerated source consistent with your
|
|
|
308
308
|
editor. Defaults are two spaces, LF, and a final newline. Push preserves authored
|
|
309
309
|
text when regeneration has the same tokens; pull preserves semantically unchanged
|
|
310
310
|
files. Formatting-only body or source-location changes do not create a subsequent
|
|
311
|
-
push
|
|
311
|
+
push, including stored initializer recipes, computed member defaults, and inline
|
|
312
|
+
constructor delegates; real code and string-content edits still do. Formatting preferences belong
|
|
312
313
|
to the checkout, not stored script bodies.
|
|
@@ -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.75.
|
|
132
|
+
<!-- reviewed-through-cli: 0.75.2 -->
|
|
130
133
|
```
|
|
131
134
|
|
|
132
135
|
The quoted version above is checked too, so this instruction cannot go stale
|
|
@@ -446,3 +446,28 @@ A lookup's declared class must be assignable to the entry class of its
|
|
|
446
446
|
selection. Constructor arguments and member initializers must select compatible
|
|
447
447
|
targets too. An `NPC` lookup cannot select from `List<Quest>`, even when its
|
|
448
448
|
initializer is typed `NPC`; status reports the conflicting collection annotation.
|
|
449
|
+
|
|
450
|
+
Schema export retains a constructed default's generic arguments, including
|
|
451
|
+
nested collection references. For example, a `NeoAnimationClip<ArmPart>`
|
|
452
|
+
default constructs `new NeoAnimationClip<ArmPart>` and its frames reference
|
|
453
|
+
`List<NeoAnimationFrame<ArmPart>>`.
|
|
454
|
+
|
|
455
|
+
When a construction leaves a required member unsettled, CLI diagnostics point to
|
|
456
|
+
`new` and include the member declaration as a related location. Fix that
|
|
457
|
+
construction before pushing. Valid root initializers still participate in
|
|
458
|
+
reference checking, so an unrelated root error does not imply their values are
|
|
459
|
+
missing or deleted. Independent reference errors remain visible.
|
|
460
|
+
|
|
461
|
+
Object initializer assignments use commas. The last comma is optional; the
|
|
462
|
+
semicolon terminating the enclosing declaration is valid:
|
|
463
|
+
|
|
464
|
+
```neo
|
|
465
|
+
AudioSettings AUDIO_SETTINGS = new() {
|
|
466
|
+
Main = new AudioMixerGroupSettingsFolder("Main", "Master", "MasterVolume", []),
|
|
467
|
+
};
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
A semicolon after `Main = ...` inside the initializer is invalid. Editor and CLI
|
|
471
|
+
diagnostics highlight that separator in the authored file, including global,
|
|
472
|
+
static member, and protected root initializers. Statement semicolons inside
|
|
473
|
+
function or delegate bodies remain valid.
|