@neocompose/cli 0.24.6 → 0.24.8

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 CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.24.8] - 2026-08-08
4
+
5
+ ### Fixed
6
+
7
+ - Preserve generated Generic-slot initializers while closing their concrete
8
+ type. `NeoAnimationSegmentFrame<int>(value: 60)` now materializes `Value` as
9
+ `60` instead of replacing the initializer with the Int binding's fallback
10
+ `0`, keeping local and server construction graphs identical.
11
+ - Keep constructor-pane preview graphs stable while runtime values change, and
12
+ invalidate each animation segment lane only from the value rows that its
13
+ getter actually reads. Direction changes update the affected leaves without
14
+ reconstructing the ephemeral character graph.
15
+
16
+ ## [0.24.7] - 2026-08-08
17
+
18
+ ### Fixed
19
+
20
+ - Lower named delegate method groups such as `this.SelectTorso` to the P60
21
+ member-target wire form, then bind their receiver to each constructed
22
+ instance. Constructor-pane previews now retain that binding when replacing
23
+ the evaluator's provisional root, so animation tracks resolve against the
24
+ ephemeral preview graph instead of disappearing.
25
+ - Reconstruct stored inline-closure `this` from the nearest compatible lexical
26
+ owner in nested declaration graphs, keeping closures distinct from named
27
+ method groups as required by P60.
28
+
3
29
  ## [0.24.6] - 2026-08-08
4
30
 
5
31
  ### Fixed
package/dist/neo.mjs CHANGED
@@ -10058,7 +10058,7 @@ var init_strict_resolver = __esm({
10058
10058
  }
10059
10059
  return void 0;
10060
10060
  }
10061
- resolveDelegateMethodGroup(expression, expected, scope) {
10061
+ resolveDelegateMethodGroup(expression, expected, scope, options = {}) {
10062
10062
  let symbol;
10063
10063
  let receiver = null;
10064
10064
  let owner;
@@ -10133,29 +10133,17 @@ var init_strict_resolver = __esm({
10133
10133
  expression.pos
10134
10134
  );
10135
10135
  }
10136
- const parameters = expected.parameterTypes.map(
10137
- (type, index) => variable(`__arg_${index}__`, type, void 0, this.project)
10136
+ if (receiver?.kind === "instance" && options.allowUnboundInstanceTarget !== true && (receiver.expression.pointer.type !== "variable" /* Variable */ || receiver.expression.pointer.variableId !== this.thisVariable.id)) {
10137
+ throw new CompileError(
10138
+ "NeoDelegate method groups currently require the current 'this' receiver.",
10139
+ expression.pos
10140
+ );
10141
+ }
10142
+ return literal(
10143
+ expected,
10144
+ { memberId: symbol.id, valueId: null },
10145
+ this.project
10138
10146
  );
10139
- const call = {
10140
- type: "callFunction" /* CallFunction */,
10141
- memberId: symbol.id,
10142
- receiver: receiver?.kind === "static" ? { kind: "static", memberId: receiver.memberId } : {
10143
- kind: "instance",
10144
- pointer: receiver?.expression.pointer ?? this.thisVariable.pointer
10145
- },
10146
- args: parameters.map((parameter4) => ({
10147
- type: "variable" /* Variable */,
10148
- variableId: parameter4.id
10149
- })),
10150
- callSiteId: this.nextCallSite(expression.pos)
10151
- };
10152
- const action = {
10153
- compilerRevision: NEOSCRIPT_COMPILER_REVISION,
10154
- parameters: [this.thisVariable, this.rootVariable, ...parameters],
10155
- instructions: expectedVoid ? [{ type: "functionCall" /* FunctionCall */, call }] : [{ type: "return" /* Return */, pointer: call }],
10156
- typeInfo: expectedVoid ? toWireType({ kind: "primitive", name: "null" }, this.project) : toWireType(expected.returnType, this.project)
10157
- };
10158
- return literal(expected, { action }, this.project);
10159
10147
  }
10160
10148
  /** Derives the exact expected delegate signature for a test mock target. */
10161
10149
  inferDelegateMethodGroupType(expression, scope) {
@@ -11830,7 +11818,10 @@ var init_strict_resolver = __esm({
11830
11818
  const target = this.resolveDelegateMethodGroup(
11831
11819
  targetAst,
11832
11820
  delegateType,
11833
- scope
11821
+ scope,
11822
+ // Mock targets are member-identity metadata. They are never invoked as
11823
+ // delegates, and mockHandle.on(receiver) owns receiver scoping.
11824
+ { allowUnboundInstanceTarget: true }
11834
11825
  );
11835
11826
  if (target === null) {
11836
11827
  throw new CompileError(
@@ -40053,6 +40044,9 @@ function substituteMember(member, env, members) {
40053
40044
  accessModifierKind: resolved.accessModifierKind,
40054
40045
  system: resolved.system ?? void 0
40055
40046
  };
40047
+ if (resolved.defaultValue !== void 0) {
40048
+ substituted.defaultValue = resolved.defaultValue;
40049
+ }
40056
40050
  const slotId = getOptionalString(member, "id");
40057
40051
  if (slotId !== void 0) {
40058
40052
  substituted.id = slotId;
@@ -42238,6 +42232,7 @@ function evaluateLiteralContainer(args) {
42238
42232
  }
42239
42233
  return {
42240
42234
  literal: literal2,
42235
+ ...evaluated.provisionalRootId === void 0 ? {} : { provisionalRootId: evaluated.provisionalRootId },
42241
42236
  ...evaluated.existingValueRow === void 0 ? {} : { existingValueRow: evaluated.existingValueRow }
42242
42237
  };
42243
42238
  }
@@ -42259,6 +42254,13 @@ function buildDefaultMemberValue(args) {
42259
42254
  return evaluated.existingValueRow;
42260
42255
  }
42261
42256
  const value2 = buildNewValue(args.projectId, evaluated.literal);
42257
+ if (evaluated.provisionalRootId !== void 0) {
42258
+ retargetDelegateReceiverValueIds(
42259
+ [value2, ...args.createdValues],
42260
+ evaluated.provisionalRootId,
42261
+ value2.id
42262
+ );
42263
+ }
42262
42264
  args.createdValues.push(value2);
42263
42265
  recordStorageKeyDeclaration(args.storageKeyDeclarations, value2.id, member);
42264
42266
  return value2;
@@ -42465,6 +42467,28 @@ function buildNewValue(projectId, body) {
42465
42467
  };
42466
42468
  return props;
42467
42469
  }
42470
+ function retargetDelegateReceiverValueIds(rows, fromValueId, toValueId) {
42471
+ const visited = /* @__PURE__ */ new WeakSet();
42472
+ const visit = (value) => {
42473
+ if (typeof value !== "object" || value === null) return;
42474
+ if (visited.has(value)) return;
42475
+ visited.add(value);
42476
+ if (isMemberDelegateTarget(value)) {
42477
+ if (value.valueId === fromValueId) value.valueId = toValueId;
42478
+ return;
42479
+ }
42480
+ if (Array.isArray(value)) {
42481
+ for (const entry of value) visit(entry);
42482
+ return;
42483
+ }
42484
+ for (const entry of Object.values(value)) visit(entry);
42485
+ };
42486
+ for (const row of rows) {
42487
+ if (!isLiteralValueContent(row)) continue;
42488
+ visit(row.value);
42489
+ visit(row.constructorArgs);
42490
+ }
42491
+ }
42468
42492
  function cloneDefaultClassRecord(args) {
42469
42493
  const sourceValue = args.sourceBody?.value;
42470
42494
  if (!isStringRecord(sourceValue)) return {};
@@ -42601,6 +42625,13 @@ function cloneDefaultValueForMember(args) {
42601
42625
  return evaluated.existingValueRow;
42602
42626
  }
42603
42627
  const evaluatedRow = buildNewValue(args.projectId, evaluated.literal);
42628
+ if (evaluated.provisionalRootId !== void 0) {
42629
+ retargetDelegateReceiverValueIds(
42630
+ [evaluatedRow, ...args.createdValues],
42631
+ evaluated.provisionalRootId,
42632
+ evaluatedRow.id
42633
+ );
42634
+ }
42604
42635
  evaluatedRow.sourceValueId = sourceValue.sourceValueId ?? args.sourceValueId;
42605
42636
  args.createdValues.push(evaluatedRow);
42606
42637
  recordStorageKeyDeclaration(
@@ -56610,7 +56641,8 @@ function evalMemberById(vm, id2) {
56610
56641
  if (vm.databaseVM?.memberById) return vm.databaseVM.memberById(id2);
56611
56642
  return vm.members.find((a) => a.id === id2) ?? null;
56612
56643
  }
56613
- function evalValueById(vm, id2, runtimeValues, overlayValues) {
56644
+ function evalValueById(ctx, id2, runtimeValues, overlayValues) {
56645
+ const vm = ctx.vm;
56614
56646
  const runtime = runtimeValues?.get(id2);
56615
56647
  if (runtime !== void 0) return runtime;
56616
56648
  const overlay = overlayValues?.get(id2);
@@ -56880,7 +56912,7 @@ function evaluatorOwnershipDistances(rowId, indexes) {
56880
56912
  }
56881
56913
  function resolveRuntimeReferenceRow(sourceValueId, ctx) {
56882
56914
  const direct = evalValueById(
56883
- ctx.vm,
56915
+ ctx,
56884
56916
  sourceValueId,
56885
56917
  ctx.__runtimeSessionValues,
56886
56918
  ctx.__valueOverlay
@@ -57319,7 +57351,7 @@ function finalizeConstructorAllocations(ctx, returnValue, ownsInvocationState, r
57319
57351
  if (scannedRows.has(valueId)) return;
57320
57352
  scannedRows.add(valueId);
57321
57353
  const row = evalValueById(
57322
- ctx.vm,
57354
+ ctx,
57323
57355
  valueId,
57324
57356
  ctx.__runtimeSessionValues,
57325
57357
  ctx.__valueOverlay
@@ -57329,7 +57361,7 @@ function finalizeConstructorAllocations(ctx, returnValue, ownsInvocationState, r
57329
57361
  const { id: argumentId, typeInfo } = argument2;
57330
57362
  if (groupByRowId.has(argumentId)) scanOwnedRow(argumentId);
57331
57363
  const argumentRow = evalValueById(
57332
- ctx.vm,
57364
+ ctx,
57333
57365
  argumentId,
57334
57366
  ctx.__runtimeSessionValues,
57335
57367
  ctx.__valueOverlay
@@ -58182,7 +58214,7 @@ function applyOverlayAssignment(target, targetTypeInfo, value, scope, ctx) {
58182
58214
  const existing2 = receiver[index];
58183
58215
  if (typeof existing2 === "string") {
58184
58216
  const row = evalValueById(
58185
- ctx.vm,
58217
+ ctx,
58186
58218
  existing2,
58187
58219
  ctx.__runtimeSessionValues,
58188
58220
  ctx.__valueOverlay
@@ -58219,7 +58251,7 @@ function applyOverlayAssignment(target, targetTypeInfo, value, scope, ctx) {
58219
58251
  const existing = object2[stringKey];
58220
58252
  if (typeof existing === "string") {
58221
58253
  const row = evalValueById(
58222
- ctx.vm,
58254
+ ctx,
58223
58255
  existing,
58224
58256
  ctx.__runtimeSessionValues,
58225
58257
  ctx.__valueOverlay
@@ -58269,7 +58301,7 @@ function applyOverlayStaticAssignment(memberId, value, ctx) {
58269
58301
  }
58270
58302
  if (!referenceAssignment && currentId !== null) {
58271
58303
  const row2 = evalValueById(
58272
- ctx.vm,
58304
+ ctx,
58273
58305
  currentId,
58274
58306
  ctx.__runtimeSessionValues,
58275
58307
  ctx.__valueOverlay
@@ -58775,7 +58807,7 @@ function evalStaticMember(memberId, ctx) {
58775
58807
  return null;
58776
58808
  }
58777
58809
  const row = evalValueById(
58778
- ctx.vm,
58810
+ ctx,
58779
58811
  targetId,
58780
58812
  ctx.__runtimeSessionValues,
58781
58813
  ctx.__valueOverlay
@@ -58785,6 +58817,7 @@ function evalStaticMember(memberId, ctx) {
58785
58817
  `Static member '${member.name}' is bound to missing value '${targetId}'.`
58786
58818
  );
58787
58819
  }
58820
+ ctx.valueDependencies?.add(row.id);
58788
58821
  return row.value;
58789
58822
  }
58790
58823
  function evalPointer(pointer, scope, ctx) {
@@ -58794,10 +58827,16 @@ function evalPointer(pointer, scope, ctx) {
58794
58827
  if (isNSDelegateClosureValue(value)) {
58795
58828
  return {
58796
58829
  ...value,
58797
- [DELEGATE_LEXICAL_THIS]: ctx.thisValue,
58830
+ ...ctx.thisValue === null || ctx.thisValue === void 0 ? {} : { [DELEGATE_LEXICAL_THIS]: ctx.thisValue },
58798
58831
  [DELEGATE_LEXICAL_ROOT]: ctx.rootValue
58799
58832
  };
58800
58833
  }
58834
+ if (isMemberDelegateTarget(value) && value.valueId === null) {
58835
+ const member = evalMemberById(ctx.vm, value.memberId);
58836
+ if (member === null || member.isStatic === true) return value;
58837
+ const receiver = trackedRowForValueReference(ctx.thisValue, ctx);
58838
+ return receiver === null ? value : { ...value, valueId: receiver.id };
58839
+ }
58801
58840
  return value;
58802
58841
  }
58803
58842
  case "variable" /* variable */: {
@@ -59064,7 +59103,7 @@ function invokeDelegateValue(value, args, ctx, callSiteId) {
59064
59103
  let receiver = null;
59065
59104
  if (value.valueId !== null) {
59066
59105
  const row = evalValueById(
59067
- ctx.vm,
59106
+ ctx,
59068
59107
  value.valueId,
59069
59108
  ctx.__runtimeSessionValues,
59070
59109
  ctx.__valueOverlay
@@ -59173,50 +59212,49 @@ function delegateClosureLexicalThis(closure, ctx) {
59173
59212
  if (Object.prototype.hasOwnProperty.call(closure, DELEGATE_LEXICAL_THIS)) {
59174
59213
  return closure[DELEGATE_LEXICAL_THIS];
59175
59214
  }
59215
+ const lexicalThisType = closure.action.parameters[0]?.typeInfo;
59216
+ if (lexicalThisType === void 0 || lexicalThisType.type === NS_TYPE_UNKNOWN || lexicalThisType.type === 0 /* Null */) {
59217
+ return null;
59218
+ }
59176
59219
  const closureRow = trackedRowForValueReference(closure, ctx);
59177
59220
  if (closureRow === null) {
59178
59221
  throw new NSGetterRuntimeError(
59179
59222
  "Stored NeoDelegate closure has no resolvable value row; lexical this cannot be reconstructed from ownership."
59180
59223
  );
59181
59224
  }
59182
- const owners = /* @__PURE__ */ new Map();
59183
- for (const link of evaluatorParentLinks(
59184
- evaluatorIndexes(ctx),
59185
- closureRow.id
59225
+ const owners = [];
59226
+ const indexes = evaluatorIndexes(ctx);
59227
+ for (const [ancestorId, distance] of evaluatorOwnershipDistances(
59228
+ closureRow.id,
59229
+ indexes
59186
59230
  )) {
59187
- const parent = evalValueById(
59188
- ctx.vm,
59189
- link.parentId,
59231
+ if (ancestorId === closureRow.id) continue;
59232
+ const ancestor = evalValueById(
59233
+ ctx,
59234
+ ancestorId,
59190
59235
  ctx.__runtimeSessionValues,
59191
59236
  ctx.__valueOverlay
59192
59237
  );
59193
- if (parent === null) continue;
59194
- if (typeof parent.value !== "object") continue;
59195
- if (parent.value === null) continue;
59196
- if (Array.isArray(parent.value)) continue;
59197
- const classId = classIdForValueRow(parent, ctx);
59198
- if (classId === void 0) continue;
59199
- const owningMember = memberForCustomSchemaValue(classId, link.key, ctx);
59200
- if (owningMember?.kind !== 25 /* NSDelegate */) continue;
59201
- owners.set(parent.id, parent.value);
59238
+ if (ancestor === null) continue;
59239
+ if (typeof ancestor.value !== "object") continue;
59240
+ if (ancestor.value === null || Array.isArray(ancestor.value)) continue;
59241
+ if (!runtimeValueMatchesType(ancestor.value, lexicalThisType, ctx))
59242
+ continue;
59243
+ owners.push({ id: ancestor.id, value: ancestor.value, distance });
59202
59244
  }
59203
- if (owners.size === 0) {
59245
+ if (owners.length === 0) {
59204
59246
  throw new NSGetterRuntimeError(
59205
59247
  `Stored NeoDelegate closure value '${closureRow.id}' has no owning class instance; lexical this cannot be reconstructed from ownership.`
59206
59248
  );
59207
59249
  }
59208
- if (owners.size > 1) {
59209
- throw new NSGetterRuntimeError(
59210
- `Stored NeoDelegate closure value '${closureRow.id}' has multiple owning class instances (${[...owners.keys()].join(", ")}); lexical this is ambiguous.`
59211
- );
59212
- }
59213
- const owner = owners.values().next();
59214
- if (owner.done) {
59250
+ const nearestDistance = Math.min(...owners.map((owner) => owner.distance));
59251
+ const nearest = owners.filter((owner) => owner.distance === nearestDistance);
59252
+ if (nearest.length > 1) {
59215
59253
  throw new NSGetterRuntimeError(
59216
- `Stored NeoDelegate closure value '${closureRow.id}' lost its owning class instance during lexical-this resolution.`
59254
+ `Stored NeoDelegate closure value '${closureRow.id}' has multiple owning class instances (${nearest.map((owner) => owner.id).join(", ")}); lexical this is ambiguous.`
59217
59255
  );
59218
59256
  }
59219
- return owner.value;
59257
+ return nearest[0].value;
59220
59258
  }
59221
59259
  function resolveCallableSignature(memberId, memberKind, ctx) {
59222
59260
  const cacheKey = `${memberKind}:${memberId}`;
@@ -59338,7 +59376,7 @@ function runtimeParentGenericEnv(row, ctx, visited) {
59338
59376
  const result = /* @__PURE__ */ new Map();
59339
59377
  for (const link of evaluatorParentLinks(evaluatorIndexes(ctx), row.id)) {
59340
59378
  const parent = evalValueById(
59341
- ctx.vm,
59379
+ ctx,
59342
59380
  link.parentId,
59343
59381
  ctx.__runtimeSessionValues,
59344
59382
  ctx.__valueOverlay
@@ -60009,12 +60047,13 @@ function resolveAssetRuntimeMember(receiver, memberName, ctx) {
60009
60047
  function resolveValueIfId(at, ctx) {
60010
60048
  if (typeof at !== "string") return at;
60011
60049
  const row = evalValueById(
60012
- ctx.vm,
60050
+ ctx,
60013
60051
  at,
60014
60052
  ctx.__runtimeSessionValues,
60015
60053
  ctx.__valueOverlay
60016
60054
  );
60017
60055
  if (!row) return at;
60056
+ ctx.valueDependencies?.add(row.id);
60018
60057
  const member = memberForValueRow(row, ctx);
60019
60058
  const value = member === null ? resolveLocalizedRowValue(row, ctx) : resolveLocalizedRowValueForMember(row, member, ctx);
60020
60059
  return shouldUnwrapSingleLookupValue(member) ? unwrapSingleLookupValue(value, ctx) : value;
@@ -60022,12 +60061,13 @@ function resolveValueIfId(at, ctx) {
60022
60061
  function resolveValueIfIdForMember(at, member, ctx) {
60023
60062
  if (typeof at !== "string") return at;
60024
60063
  const row = evalValueById(
60025
- ctx.vm,
60064
+ ctx,
60026
60065
  at,
60027
60066
  ctx.__runtimeSessionValues,
60028
60067
  ctx.__valueOverlay
60029
60068
  );
60030
60069
  if (!row) return at;
60070
+ ctx.valueDependencies?.add(row.id);
60031
60071
  const value = resolveLocalizedRowValueForMember(row, member, ctx);
60032
60072
  return shouldUnwrapSingleLookupValue(member) ? unwrapSingleLookupValue(value, ctx) : value;
60033
60073
  }
@@ -60039,12 +60079,15 @@ function shouldUnwrapSingleLookupValue(member) {
60039
60079
  function unwrapSingleLookupValue(value, ctx) {
60040
60080
  if (Array.isArray(value) && value.length === 1 && typeof value[0] === "string") {
60041
60081
  const next = evalValueById(
60042
- ctx.vm,
60082
+ ctx,
60043
60083
  value[0],
60044
60084
  ctx.__runtimeSessionValues,
60045
60085
  ctx.__valueOverlay
60046
60086
  );
60047
- if (next) return next.value;
60087
+ if (next) {
60088
+ ctx.valueDependencies?.add(next.id);
60089
+ return next.value;
60090
+ }
60048
60091
  }
60049
60092
  return value;
60050
60093
  }
@@ -60085,7 +60128,7 @@ function resolveMemberForValueRow(row, ctx, visited) {
60085
60128
  }
60086
60129
  for (const link of evaluatorParentLinks(indexes, row.id)) {
60087
60130
  const parent = evalValueById(
60088
- ctx.vm,
60131
+ ctx,
60089
60132
  link.parentId,
60090
60133
  ctx.__runtimeSessionValues,
60091
60134
  ctx.__valueOverlay
@@ -60410,7 +60453,7 @@ function evalDeclaredListIndex(info, scope, ctx) {
60410
60453
  for (const valueId of collection) {
60411
60454
  if (typeof valueId !== "string") continue;
60412
60455
  const row = evalValueById(
60413
- ctx.vm,
60456
+ ctx,
60414
60457
  valueId,
60415
60458
  ctx.__runtimeSessionValues,
60416
60459
  ctx.__valueOverlay
@@ -60995,7 +61038,7 @@ function applyConstructorFields(args) {
60995
61038
  const trackedValueId = findKnownRowIdByValueReference(value, ctx);
60996
61039
  if (trackedValueId !== null && isMemberClassBase(member)) {
60997
61040
  const source = evalValueById(
60998
- ctx.vm,
61041
+ ctx,
60999
61042
  trackedValueId,
61000
61043
  ctx.__runtimeSessionValues,
61001
61044
  ctx.__valueOverlay
@@ -61097,6 +61140,74 @@ function stageConstructedRows(createdValues, ctx) {
61097
61140
  if (ctx.__indexes !== void 0) indexEvaluatorRow(ctx.__indexes, row);
61098
61141
  }
61099
61142
  }
61143
+ function bindConstructedDelegateTargets(rootId, ctx) {
61144
+ const indexes = evaluatorIndexes(ctx);
61145
+ const pending = [rootId];
61146
+ const visited = /* @__PURE__ */ new Set();
61147
+ while (pending.length > 0) {
61148
+ const rowId = pending.pop();
61149
+ if (rowId === void 0 || visited.has(rowId)) continue;
61150
+ visited.add(rowId);
61151
+ const row = evalValueById(
61152
+ ctx,
61153
+ rowId,
61154
+ ctx.__runtimeSessionValues,
61155
+ ctx.__valueOverlay
61156
+ );
61157
+ if (row === null) continue;
61158
+ if (Array.isArray(row.value)) {
61159
+ for (const childId of row.value) {
61160
+ if (typeof childId === "string") pending.push(childId);
61161
+ }
61162
+ } else if (typeof row.value === "object" && row.value !== null) {
61163
+ for (const childId of Object.values(row.value)) {
61164
+ if (typeof childId === "string") pending.push(childId);
61165
+ }
61166
+ }
61167
+ if (!isMemberDelegateTarget(row.value) || row.value.valueId !== null) {
61168
+ continue;
61169
+ }
61170
+ const target = evalMemberById(ctx.vm, row.value.memberId);
61171
+ if (target === null || target.isStatic === true) continue;
61172
+ const placement = findSchemaPlacement(target.id, ctx.vm.classes);
61173
+ if (placement === null) {
61174
+ throw new NSGetterRuntimeError(
61175
+ `NeoDelegate method target '${target.name}' has no declaring Class placement.`
61176
+ );
61177
+ }
61178
+ const matches = [];
61179
+ for (const [ancestorId, distance] of evaluatorOwnershipDistances(
61180
+ row.id,
61181
+ indexes
61182
+ )) {
61183
+ const ancestor = evalValueById(
61184
+ ctx,
61185
+ ancestorId,
61186
+ ctx.__runtimeSessionValues,
61187
+ ctx.__valueOverlay
61188
+ );
61189
+ if (ancestor === null) continue;
61190
+ const ancestorClassId = classIdForValueRow(ancestor, ctx);
61191
+ if (ancestorClassId === void 0) continue;
61192
+ const ownsTarget = resolveInheritanceChain(
61193
+ ancestorClassId,
61194
+ ctx.vm.classes
61195
+ ).some((schemaClass2) => schemaClass2.id === placement.ownerClass.id);
61196
+ if (ownsTarget) matches.push({ id: ancestor.id, distance });
61197
+ }
61198
+ if (matches.length === 0) continue;
61199
+ const nearestDistance = Math.min(...matches.map((match) => match.distance));
61200
+ const nearest = matches.filter(
61201
+ (match) => match.distance === nearestDistance
61202
+ );
61203
+ if (nearest.length !== 1) {
61204
+ throw new NSGetterRuntimeError(
61205
+ `NeoDelegate method target '${target.name}' has multiple equally near receiver instances (${nearest.map((match) => match.id).join(", ")}).`
61206
+ );
61207
+ }
61208
+ row.value = { ...row.value, valueId: nearest[0].id };
61209
+ }
61210
+ }
61100
61211
  function publishConstructedRows(args) {
61101
61212
  const { root, createdValues, ctx } = args;
61102
61213
  assertConstructorRowsHaveSingleStructuralOwner(createdValues, ctx);
@@ -61158,6 +61269,7 @@ function publishConstructedRows(args) {
61158
61269
  destination.set(row.id, row);
61159
61270
  if (ctx.__indexes !== void 0) indexEvaluatorRow(ctx.__indexes, row);
61160
61271
  }
61272
+ bindConstructedDelegateTargets(root.id, ctx);
61161
61273
  state.constructorGroups.set(root.id, retained);
61162
61274
  state.ownedValueAttachments.clear();
61163
61275
  }
@@ -61855,6 +61967,7 @@ function evaluateInitializerInContext(init, member, ctx, createdValues, argument
61855
61967
  return {
61856
61968
  value: result.value,
61857
61969
  classId: rootRow.classId ?? null,
61970
+ provisionalRootId: rootRow.id,
61858
61971
  ...constructorArgs === void 0 ? {} : { constructorArgs: structuredClone(constructorArgs) }
61859
61972
  };
61860
61973
  }
@@ -62146,6 +62259,7 @@ function constructDeclaredClassValueWithinFrame(descriptor, record3, info, scope
62146
62259
  root.constructorArgs = structuredClone(encoded);
62147
62260
  }
62148
62261
  stageConstructedRows(createdValues, ctx);
62262
+ bindConstructedDelegateTargets(root.id, ctx);
62149
62263
  if (record3 !== null) {
62150
62264
  runDeclaredConstructorChain({
62151
62265
  record: record3,
@@ -62214,7 +62328,7 @@ function constructDeclaredClassValueWithinFrame(descriptor, record3, info, scope
62214
62328
  }
62215
62329
  function assertOwnedValueAttachable(valueId, destination, destinationName2, ctx, reserveUntilPublished = false) {
62216
62330
  const row = evalValueById(
62217
- ctx.vm,
62331
+ ctx,
62218
62332
  valueId,
62219
62333
  ctx.__runtimeSessionValues,
62220
62334
  ctx.__valueOverlay
@@ -62260,7 +62374,7 @@ function currentOwnedValueAttachments(valueId, ctx) {
62260
62374
  found.set(attachment.identity, attachment);
62261
62375
  };
62262
62376
  const row = evalValueById(
62263
- ctx.vm,
62377
+ ctx,
62264
62378
  valueId,
62265
62379
  ctx.__runtimeSessionValues,
62266
62380
  ctx.__valueOverlay
@@ -62297,7 +62411,7 @@ function currentOwnedValueAttachments(valueId, ctx) {
62297
62411
  );
62298
62412
  for (const parentId of parentIds) {
62299
62413
  const parent = evalValueById(
62300
- ctx.vm,
62414
+ ctx,
62301
62415
  parentId,
62302
62416
  ctx.__runtimeSessionValues,
62303
62417
  ctx.__valueOverlay
@@ -62365,7 +62479,7 @@ function constructorArgumentStorage(valueId, ctx, visiting = /* @__PURE__ */ new
62365
62479
  if (visiting.has(valueId)) return null;
62366
62480
  visiting.add(valueId);
62367
62481
  const row = evalValueById(
62368
- ctx.vm,
62482
+ ctx,
62369
62483
  valueId,
62370
62484
  ctx.__runtimeSessionValues,
62371
62485
  ctx.__valueOverlay
@@ -62387,7 +62501,7 @@ function constructorArgumentStorage(valueId, ctx, visiting = /* @__PURE__ */ new
62387
62501
  const parentIds = /* @__PURE__ */ new Set();
62388
62502
  for (const owner of currentOwnedValueAttachments(valueId, ctx)) {
62389
62503
  if (evalValueById(
62390
- ctx.vm,
62504
+ ctx,
62391
62505
  owner.label,
62392
62506
  ctx.__runtimeSessionValues,
62393
62507
  ctx.__valueOverlay
@@ -62497,7 +62611,7 @@ function cloneConstructorArgumentGraph(args) {
62497
62611
  args.ctx
62498
62612
  );
62499
62613
  const child = evalValueById(
62500
- args.ctx.vm,
62614
+ args.ctx,
62501
62615
  childId,
62502
62616
  args.ctx.__runtimeSessionValues,
62503
62617
  args.ctx.__valueOverlay
@@ -62533,7 +62647,7 @@ function cloneConstructorArgumentGraph(args) {
62533
62647
  );
62534
62648
  }
62535
62649
  const child = evalValueById(
62536
- args.ctx.vm,
62650
+ args.ctx,
62537
62651
  childId,
62538
62652
  args.ctx.__runtimeSessionValues,
62539
62653
  args.ctx.__valueOverlay
@@ -62580,7 +62694,7 @@ function cloneConstructorArgumentGraph(args) {
62580
62694
  );
62581
62695
  }
62582
62696
  const child = evalValueById(
62583
- args.ctx.vm,
62697
+ args.ctx,
62584
62698
  childId,
62585
62699
  args.ctx.__runtimeSessionValues,
62586
62700
  args.ctx.__valueOverlay
@@ -62622,7 +62736,7 @@ function materializeConstructorArgumentValue(args) {
62622
62736
  }
62623
62737
  if (trackedValueId !== null) {
62624
62738
  const tracked = evalValueById(
62625
- args.ctx.vm,
62739
+ args.ctx,
62626
62740
  trackedValueId,
62627
62741
  args.ctx.__runtimeSessionValues,
62628
62742
  args.ctx.__valueOverlay
@@ -62805,7 +62919,7 @@ function assertConstructorClassValueAdmitted(args) {
62805
62919
  function constructorCollectionEntryValue(value, ctx, resolveStoredId) {
62806
62920
  if (!resolveStoredId || typeof value !== "string") return value;
62807
62921
  const row = evalValueById(
62808
- ctx.vm,
62922
+ ctx,
62809
62923
  value,
62810
62924
  ctx.__runtimeSessionValues,
62811
62925
  ctx.__valueOverlay
@@ -62855,7 +62969,7 @@ function cloneClassValueGraph(receiver, expectedClassId, ctx) {
62855
62969
  );
62856
62970
  }
62857
62971
  const source = evalValueById(
62858
- ctx.vm,
62972
+ ctx,
62859
62973
  sourceId3,
62860
62974
  ctx.__runtimeSessionValues,
62861
62975
  ctx.__valueOverlay
@@ -62920,7 +63034,7 @@ function cloneClassValueGraph(receiver, expectedClassId, ctx) {
62920
63034
  const childTypeInfo = sourceTypeInfo?.type === 5 /* Dictionary */ ? sourceTypeInfo.entryTypeInfo : void 0;
62921
63035
  if (childMember === null && childTypeInfo === void 0) continue;
62922
63036
  const child = evalValueById(
62923
- ctx.vm,
63037
+ ctx,
62924
63038
  childId,
62925
63039
  ctx.__runtimeSessionValues,
62926
63040
  ctx.__valueOverlay
@@ -62941,7 +63055,7 @@ function cloneClassValueGraph(receiver, expectedClassId, ctx) {
62941
63055
  clone.value = sourceRow.value.map((childId) => {
62942
63056
  if (typeof childId !== "string") return childId;
62943
63057
  const child = evalValueById(
62944
- ctx.vm,
63058
+ ctx,
62945
63059
  childId,
62946
63060
  ctx.__runtimeSessionValues,
62947
63061
  ctx.__valueOverlay
@@ -62971,7 +63085,7 @@ function cloneClassValueGraph(receiver, expectedClassId, ctx) {
62971
63085
  }
62972
63086
  if (constructorArgumentReferenceCounts.get(argument2.id) !== 1) continue;
62973
63087
  const argumentRow = evalValueById(
62974
- ctx.vm,
63088
+ ctx,
62975
63089
  argument2.id,
62976
63090
  ctx.__runtimeSessionValues,
62977
63091
  ctx.__valueOverlay
@@ -63430,6 +63544,7 @@ function evaluateMemberInitializer(args) {
63430
63544
  return {
63431
63545
  value: result.value,
63432
63546
  classId: rootRow.classId ?? null,
63547
+ provisionalRootId: rootRow.id,
63433
63548
  ...constructorArgs === void 0 ? {} : { constructorArgs: structuredClone(constructorArgs) }
63434
63549
  };
63435
63550
  }
@@ -63490,6 +63605,13 @@ function materializeInitializerValue(args) {
63490
63605
  ...evaluated.classId === null ? {} : { classId: evaluated.classId },
63491
63606
  ...evaluated.constructorArgs === void 0 ? {} : { constructorArgs: structuredClone(evaluated.constructorArgs) }
63492
63607
  };
63608
+ if (evaluated.provisionalRootId !== void 0) {
63609
+ retargetDelegateReceiverValueIds(
63610
+ [root, ...createdValues],
63611
+ evaluated.provisionalRootId,
63612
+ root.id
63613
+ );
63614
+ }
63493
63615
  const allCreated = [root, ...createdValues];
63494
63616
  for (const created of createdValues) {
63495
63617
  if (created.classId === void 0) delete created.classId;
@@ -88472,13 +88594,15 @@ function lowerFunctionReference(context, expression, ownerClassId) {
88472
88594
  return { functionMemberId: target.id };
88473
88595
  }
88474
88596
  function lowerDelegateValue(context, expression, ownerClassId, authoredSlice) {
88475
- const code = initializerExpressionSlice(authoredSlice);
88476
- if (code === void 0) {
88477
- throw new Error(
88478
- "Delegate values require recoverable authored source so the server can compile their lexical receiver."
88479
- );
88597
+ if (expression.kind === "lambda") {
88598
+ const code = initializerExpressionSlice(authoredSlice);
88599
+ if (code === void 0) {
88600
+ throw new Error(
88601
+ "Delegate lambdas require recoverable authored source so the server can compile their closure."
88602
+ );
88603
+ }
88604
+ return { code };
88480
88605
  }
88481
- if (expression.kind === "lambda") return { code };
88482
88606
  const path = memberPath(expression);
88483
88607
  const symbol = path?.startsWith("this.") ? path.slice("this.".length) : path;
88484
88608
  if (symbol === null || symbol === void 0 || symbol.includes(".")) {
@@ -88497,7 +88621,7 @@ function lowerDelegateValue(context, expression, ownerClassId, authoredSlice) {
88497
88621
  `Delegate ${symbol} does not resolve to a function, NSFunction, or NSDelegate member.`
88498
88622
  );
88499
88623
  }
88500
- return { code };
88624
+ return { memberId: target.id, valueId: null };
88501
88625
  }
88502
88626
  function fileTargetId(context, expression, registry) {
88503
88627
  const path = memberPath(expression);
@@ -101546,7 +101670,7 @@ var init_registry2 = __esm({
101546
101670
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
101547
101671
  formatVersion: 3,
101548
101672
  contractVersion: "3.9",
101549
- cliVersion: "0.24.6",
101673
+ cliVersion: "0.24.8",
101550
101674
  projectFileUploadBatchSize: 32,
101551
101675
  documentRecords: {
101552
101676
  member: {
@@ -102951,21 +103075,7 @@ function errorMessage2(error) {
102951
103075
  return error instanceof Error ? error.message : String(error);
102952
103076
  }
102953
103077
  function findDelegateTargetMemberId(value) {
102954
- if (!isRecord10(value) || !isRecord10(value.action)) return null;
102955
- const pending = [value.action.instructions];
102956
- while (pending.length > 0) {
102957
- const current = pending.shift();
102958
- if (Array.isArray(current)) {
102959
- pending.push(...current);
102960
- continue;
102961
- }
102962
- if (!isRecord10(current)) continue;
102963
- if (current.type === "callFunction" && typeof current.memberId === "string") {
102964
- return current.memberId;
102965
- }
102966
- pending.push(...Object.values(current));
102967
- }
102968
- return null;
103078
+ return isRecord10(value) && typeof value.memberId === "string" ? value.memberId : null;
102969
103079
  }
102970
103080
  function makeEvaluatorContext(rawDocument, interceptor, documentAlreadyIsolated = false) {
102971
103081
  const isolatedDocument = documentAlreadyIsolated ? rawDocument : structuredClone(rawDocument);
@@ -104081,7 +104191,7 @@ async function runTest(workspace, options, dependencies = {}) {
104081
104191
  cliVersion: PROJECT_SCHEMA_CONTRACT.cliVersion,
104082
104192
  runnerRevision: 3,
104083
104193
  compilerRevision: NEOSCRIPT_COMPILER_REVISION,
104084
- evaluatorRevision: 3,
104194
+ evaluatorRevision: 4,
104085
104195
  projectFingerprint,
104086
104196
  configurationSha256: createHash10("sha256").update(JSON.stringify(workspace.config.test ?? {})).digest("hex"),
104087
104197
  dependencyGraph: Object.fromEntries(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.24.6",
3
+ "version": "0.24.8",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -9,7 +9,7 @@ description: >-
9
9
  `@neocompose/cli` or `node cli/bin/neo.mjs` in the neo-compose repository.
10
10
  ---
11
11
 
12
- <!-- reviewed-through-cli: 0.24.6 -->
12
+ <!-- reviewed-through-cli: 0.24.8 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -127,6 +127,10 @@ Use `NeoAnimationSegment<T>` for a frame-indexed value lane. The shipped
127
127
  sprite specialization is `NeoSpriteAnimationSegment`, whose
128
128
  `NeoAnimationSegmentFrame<SpriteInfo>` rows each provide `Index` and
129
129
  `Value`. Sparse frame values hold until the next row or `Duration`.
130
+ Pass `Value` through the frame constructor (for example,
131
+ `new NeoAnimationSegmentFrame<int>(value: 60)`). The constructor argument is
132
+ the frame's authored value; it must not collapse to the concrete generic
133
+ binding's fallback while the segment is materialized.
130
134
 
131
135
  Use one polymorphic `NeoAnimationClip.Tracks` list:
132
136
 
@@ -181,9 +185,11 @@ pulled rows.
181
185
  A selector argument such as `this.SelectPants` is evaluated in the lexical
182
186
  scope of the class that declares the clip. Here `this` is the `LegPart`, not
183
187
  the nested track row or an outer object instance that later receives a copy of
184
- the declaration default. Keep that named method group as authored delegate
185
- source through lowering so construction can capture each concrete `LegPart`;
186
- an unbound member target has no instance on which to invoke the selector.
188
+ the declaration default. A named method group lowers to the P60 member-target
189
+ form. Its declaration default carries `valueId: null` because no instance row
190
+ exists yet; materializing the declaration binds it to the concrete `LegPart`
191
+ row. An inline closure remains compiled closure source and reconstructs its
192
+ lexical owner from the materialized graph. Do not interchange these two forms.
187
193
 
188
194
  Each track has `StartFrame`, `Direction` (`.Forward` or `.Reverse`), and a
189
195
  crop window `OffsetStartIndex`/`OffsetEndIndex`. Crop before reversing, then
@@ -82,7 +82,7 @@ wrappers.
82
82
  The marker near the top of `SKILL.md` must exactly match the package version:
83
83
 
84
84
  ```html
85
- <!-- reviewed-through-cli: 0.24.6 -->
85
+ <!-- reviewed-through-cli: 0.24.8 -->
86
86
  ```
87
87
 
88
88
  The quoted version above is checked too, so this instruction cannot go stale