@neocompose/cli 0.89.9 → 0.89.10

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,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.89.10
4
+
5
+ ### Patch Changes
6
+
7
+ - e676c54: Preserve explicit child-override types when selectors return local variables or use other equivalent bodies, including typed partial overrides and source round trips.
8
+ - af6aa88: Validate delegate bodies inside variant and generic constructor arguments in the editor. Bind child selectors and method groups to the variant target, preserve concrete child types through preparation, and execute constructor-backed child overrides without requiring authored IDs.
9
+
3
10
  ## 0.89.9
4
11
 
5
12
  ### Patch Changes
@@ -19371,7 +19371,7 @@ var init_registry = __esm({
19371
19371
  "../packages/manifest/schema-contract/registry.mjs"() {
19372
19372
  "use strict";
19373
19373
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
19374
- cliVersion: "0.89.9",
19374
+ cliVersion: "0.89.10",
19375
19375
  projectFileUploadBatchSize: 32,
19376
19376
  documentRecords: {
19377
19377
  member: {
@@ -52473,6 +52473,16 @@ function readVariantSelection(value, label) {
52473
52473
  }
52474
52474
  return { classId, variantId, rowValueId: rowValueId ?? null };
52475
52475
  }
52476
+ function variantConstructorRecord(row, schemaKeys) {
52477
+ const recipe = isLiteralValueContent(row) ? row.constructorArgs : void 0;
52478
+ const result = {};
52479
+ if (recipe == null) return result;
52480
+ for (let index = 0; index < schemaKeys.length; index++) {
52481
+ const argument2 = recipe[`__arg_${index}__`];
52482
+ if (argument2 !== void 0) result[schemaKeys[index]] = argument2;
52483
+ }
52484
+ return result;
52485
+ }
52476
52486
  function resolveVariantGraph(selection2, ctx) {
52477
52487
  const variantId = selection2.variantId;
52478
52488
  if (variantId === null) {
@@ -52510,20 +52520,14 @@ function resolveVariantGraph(selection2, ctx) {
52510
52520
  );
52511
52521
  }
52512
52522
  const effectiveRoot = { ...root };
52513
- const recipe = row.constructorArgs;
52514
- if (typeof recipe === "object" && recipe !== null) {
52515
- const settledVariantSlots = [
52516
- ["Initialize", 0],
52517
- ["Apply", 1],
52518
- ["Overrides", 2],
52519
- ["ChildOverrides", 3]
52520
- ];
52521
- for (const [schemaKey, argumentIndex] of settledVariantSlots) {
52522
- if (effectiveRoot[schemaKey] !== void 0) continue;
52523
- const argument2 = recipe[`__arg_${argumentIndex}__`];
52524
- if (argument2 === void 0 || argument2 === null) continue;
52525
- effectiveRoot[schemaKey] = argument2;
52526
- }
52523
+ const recipe = variantConstructorRecord(row, [
52524
+ "Initialize",
52525
+ "Apply",
52526
+ "Overrides",
52527
+ "ChildOverrides"
52528
+ ]);
52529
+ for (const [key, value] of Object.entries(recipe)) {
52530
+ if (effectiveRoot[key] === void 0) effectiveRoot[key] = value;
52527
52531
  }
52528
52532
  return {
52529
52533
  variantId,
@@ -52618,7 +52622,7 @@ function invokeVariantClosure(args) {
52618
52622
  [DELEGATE_LEXICAL_THIS]: lexicalThis,
52619
52623
  [DELEGATE_LEXICAL_ROOT]: ctx.rootValue
52620
52624
  };
52621
- return invokeDelegateValue(bound, parameters, ctx);
52625
+ return invokeDelegateValue(bound, parameters, ctx, void 0, lexicalThis);
52622
52626
  }
52623
52627
  function writeVariantOverrideSlot(target, schemaKey, value, ctx, answeredValueIds) {
52624
52628
  assertStoredReplayMutableValue(target, ctx, "variant override", schemaKey);
@@ -52814,6 +52818,32 @@ function replacesInterfaceSlotRow(member, target, overrideRow, ctx) {
52814
52818
  if (targetRow === null) return false;
52815
52819
  return classIdForValueRow(targetRow, ctx) !== overrideRow.classId;
52816
52820
  }
52821
+ function readVariantChildOverrideSlot(entryRow, schemaKey, ctx) {
52822
+ const entry = readRowValue(entryRow, ctx);
52823
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry))
52824
+ return null;
52825
+ const classId = classIdForValueRow(entryRow, ctx);
52826
+ const memberId = classId == null ? null : cachedMergedSchemaMemberId(classId, schemaKey, ctx);
52827
+ const member = memberId === null ? null : evalMemberById(ctx.vm, memberId);
52828
+ if (member === null) {
52829
+ throw new NSGetterRuntimeError(
52830
+ `Child override '${entryRow.id}' has no '${schemaKey}' member.`
52831
+ );
52832
+ }
52833
+ const slot = readClassMember({
52834
+ member,
52835
+ schemaKey,
52836
+ record: entry,
52837
+ expandedRecord: () => variantConstructorRecord(entryRow, ["Selector", "Overrides"]),
52838
+ mode: "runtime"
52839
+ });
52840
+ if (slot.kind === "value") return slot.value;
52841
+ if (slot.kind === "declaration") {
52842
+ const result = readDeclarationDefault(member, ctx);
52843
+ return result.matched ? result.value : null;
52844
+ }
52845
+ return null;
52846
+ }
52817
52847
  function applyVariantDeclarativeHalves(instance, graph, ctx, answeredValueIds) {
52818
52848
  applyVariantPartial(
52819
52849
  instance,
@@ -52852,14 +52882,13 @@ function applyVariantDeclarativeHalves(instance, graph, ctx, answeredValueIds) {
52852
52882
  `Variant '${graph.name}' references missing child-override row '${entryId}'.`
52853
52883
  );
52854
52884
  }
52855
- const entry = entryRow.value;
52885
+ const entry = readRowValue(entryRow, ctx);
52856
52886
  if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
52857
52887
  continue;
52858
52888
  }
52859
- const entryRecord = entry;
52860
52889
  const label = `Variant '${graph.name}' child override '${entryId}'`;
52861
52890
  const child2 = invokeVariantClosure({
52862
- closureValueId: entryRecord.Selector,
52891
+ closureValueId: readVariantChildOverrideSlot(entryRow, "Selector", ctx),
52863
52892
  ctx,
52864
52893
  label: `${label} Selector`,
52865
52894
  lexicalThis: instance,
@@ -52872,7 +52901,7 @@ function applyVariantDeclarativeHalves(instance, graph, ctx, answeredValueIds) {
52872
52901
  }
52873
52902
  applyVariantPartial(
52874
52903
  child2,
52875
- entryRecord.Overrides,
52904
+ readVariantChildOverrideSlot(entryRow, "Overrides", ctx),
52876
52905
  ctx,
52877
52906
  label,
52878
52907
  answeredValueIds
@@ -52994,7 +53023,7 @@ function collectVariantDeclarativeAnsweredSlots(instance, graph, ctx) {
52994
53023
  }
52995
53024
  const label = `Variant '${graph.name}' child override '${entryId}'`;
52996
53025
  const child2 = invokeVariantClosure({
52997
- closureValueId: Reflect.get(entryRow.value, "Selector"),
53026
+ closureValueId: readVariantChildOverrideSlot(entryRow, "Selector", ctx),
52998
53027
  ctx,
52999
53028
  label: `${label} Selector`,
53000
53029
  lexicalThis: instance,
@@ -53007,7 +53036,7 @@ function collectVariantDeclarativeAnsweredSlots(instance, graph, ctx) {
53007
53036
  }
53008
53037
  collectVariantPartialAnsweredSlots(
53009
53038
  child2,
53010
- Reflect.get(entryRow.value, "Overrides"),
53039
+ readVariantChildOverrideSlot(entryRow, "Overrides", ctx),
53011
53040
  ctx,
53012
53041
  label,
53013
53042
  slots
@@ -90865,7 +90894,7 @@ var init_neoscript_language_context_adapter = __esm({
90865
90894
  init_dialogue_types();
90866
90895
  init_dialogue_group_language();
90867
90896
  init_analyzer_types();
90868
- NEOSCRIPT_COMPILER_ADAPTER_REVISION = 7;
90897
+ NEOSCRIPT_COMPILER_ADAPTER_REVISION = 8;
90869
90898
  UNKNOWN_TYPE2 = {
90870
90899
  kind: "primitive",
90871
90900
  name: "unknown"
@@ -98903,10 +98932,8 @@ function knownGeneratorExpression(expression, scope, environment) {
98903
98932
  function validateExpression(expression, expected, scope, environment, uri, range2, diagnostics, anchor, storedValue = true) {
98904
98933
  const sourceOnly = expected !== void 0 && (isNeoVariantTypeName(expected.name) || expected.name === "NeoAction" || expected.name === "ImageRef");
98905
98934
  let receiver = expression;
98906
- if (environment.checkComputedInitializers) {
98907
- while (receiver.kind === "member") receiver = receiver.receiver;
98908
- }
98909
- const computed = environment.checkComputedInitializers && !sourceOnly && (expression.kind === "member" && (receiver.kind !== "ident" || receiver.typeQualifier !== void 0) || [
98935
+ while (receiver.kind === "member") receiver = receiver.receiver;
98936
+ const computed = (environment.checkComputedInitializers || expected?.name === "NeoDelegate") && !sourceOnly && (expression.kind === "member" && (receiver.kind !== "ident" || receiver.typeQualifier !== void 0) || [
98910
98937
  "binary",
98911
98938
  "unary",
98912
98939
  "force",
@@ -99521,7 +99548,7 @@ function validateStoredExpression(expression, expected, scope, environment, uri,
99521
99548
  }
99522
99549
  expression.args.forEach((argument2, index) => {
99523
99550
  const authoredName = expression.argumentNames?.[index];
99524
- const named = declaration.name === NEO_LOOKUP_VARIANT_FOLDER_TYPE_NAME ? authoredName ?? NEO_LOOKUP_VARIANT_FOLDER_CONSTRUCTOR_ARGUMENTS[index]?.name : authoredName;
99551
+ const named = declaration.name === NEO_LOOKUP_VARIANT_FOLDER_TYPE_NAME ? authoredName ?? NEO_LOOKUP_VARIANT_FOLDER_CONSTRUCTOR_ARGUMENTS[index]?.name : authoredName ?? parameters?.[index]?.name;
99525
99552
  if (declaration.name === NEO_LOOKUP_VARIANT_FOLDER_TYPE_NAME && named === "collection") {
99526
99553
  return;
99527
99554
  }
@@ -99554,7 +99581,7 @@ function validateStoredExpression(expression, expected, scope, environment, uri,
99554
99581
  entry,
99555
99582
  void 0,
99556
99583
  scope,
99557
- environment,
99584
+ { ...environment, variantSelectorThis: siteTypeArguments[0] },
99558
99585
  uri,
99559
99586
  range2,
99560
99587
  diagnostics,
@@ -99606,11 +99633,12 @@ function validateStoredExpression(expression, expected, scope, environment, uri,
99606
99633
  return;
99607
99634
  }
99608
99635
  }
99636
+ const selectorThis = declaration.name === NEO_ANIMATION_CHILD_OVERRIDE_TYPE_NAME && named === "selector" ? environment.variantSelectorThis : void 0;
99609
99637
  validateExpression(
99610
99638
  argument2,
99611
99639
  expectedSemanticType,
99612
- scope,
99613
- environment,
99640
+ selectorThis === void 0 ? scope : new Map(scope).set("this", selectorThis),
99641
+ selectorThis === void 0 ? environment : { ...environment, staticMember: false },
99614
99642
  uri,
99615
99643
  range2,
99616
99644
  diagnostics,
@@ -149898,7 +149926,9 @@ function compileInlineDelegateConstructorArguments(args) {
149898
149926
  );
149899
149927
  }
149900
149928
  const env = isClassSlotMember(ownerMember) ? slotRowEnv(ownerMember, row, document).env : resolveInstanceEnv(classId, void 0, document.classes);
149901
- const thisClass = findSchemaPlacement(rootOwner?.id ?? "", document.classes)?.ownerClass ?? null;
149929
+ for (const [paramId, memberId] of Object.entries(row.genericBindings ?? {})) {
149930
+ env.set(paramId, { kind: "member", memberId });
149931
+ }
149902
149932
  const compiled = { ...constructorArgs2 };
149903
149933
  for (const [argumentKey, argument2] of Object.entries(constructorArgs2)) {
149904
149934
  if (!isUncompiledInlineDelegateArgument(argument2)) continue;
@@ -149945,7 +149975,7 @@ function compileInlineDelegateConstructorArguments(args) {
149945
149975
  constructors: document.constructors ?? [],
149946
149976
  variants: document.variants ?? [],
149947
149977
  variantFolders: document.variantFolders ?? [],
149948
- thisClass,
149978
+ thisClass: args.thisClassForMember(settledMember),
149949
149979
  returnTypeInfo: substituted.returnTypeInfo,
149950
149980
  argumentTypes: substituted.argumentTypes,
149951
149981
  name: `${settledMember.name} argument`,
@@ -150026,6 +150056,29 @@ function compileValueBodies(args) {
150026
150056
  function createDelegateValueBodyCompiler(postDocument, targetIds, prepared) {
150027
150057
  const scope = prepared ?? delegateValueBodyOwnership(postDocument, targetIds);
150028
150058
  const { ownerByValueId, rootOwnerByValueId } = scope;
150059
+ const variantSelectorScopes = /* @__PURE__ */ new WeakMap();
150060
+ const thisClassForMember = (document, rootOwner, memberId) => {
150061
+ let selectors = variantSelectorScopes.get(document);
150062
+ if (selectors === void 0) {
150063
+ const classes = new Map(document.classes.map((type2) => [type2.id, type2]));
150064
+ const selectorId = document.classes.find(
150065
+ (type2) => type2.system?.worldKind === "animationChildOverride"
150066
+ )?.schema.Selector;
150067
+ const targets = /* @__PURE__ */ new Map();
150068
+ for (const variant2 of document.variants ?? []) {
150069
+ const target = classes.get(variant2.classId);
150070
+ if (target !== void 0)
150071
+ targets.set(variantRootMemberId(variant2.id), target);
150072
+ }
150073
+ selectors = { selectorId, targets };
150074
+ variantSelectorScopes.set(document, selectors);
150075
+ }
150076
+ if (memberId !== void 0 && memberId === selectors.selectorId && rootOwner !== void 0) {
150077
+ const target = selectors.targets.get(rootOwner.id);
150078
+ if (target !== void 0) return target;
150079
+ }
150080
+ return findSchemaPlacement(rootOwner?.id ?? "", document.classes)?.ownerClass ?? null;
150081
+ };
150029
150082
  const compilationProjects = /* @__PURE__ */ new WeakMap();
150030
150083
  if (prepared !== void 0)
150031
150084
  compilationProjects.set(prepared.document, prepared.compilationProject);
@@ -150046,7 +150099,11 @@ function createDelegateValueBodyCompiler(postDocument, targetIds, prepared) {
150046
150099
  );
150047
150100
  }
150048
150101
  const rootOwner = rootOwnerByValueId.get(row.id);
150049
- const thisClass = findSchemaPlacement(rootOwner?.id ?? "", document.classes)?.ownerClass ?? null;
150102
+ const thisClass = thisClassForMember(
150103
+ document,
150104
+ rootOwner,
150105
+ getOptionalString(member, "id")
150106
+ );
150050
150107
  const compiled = { ...row, value: { ...row.value } };
150051
150108
  try {
150052
150109
  compiled.value = compileDelegateClosureValue(row.value.code, {
@@ -150086,6 +150143,7 @@ function createDelegateValueBodyCompiler(postDocument, targetIds, prepared) {
150086
150143
  row,
150087
150144
  ownerMember: ownerByValueId.get(row.id),
150088
150145
  rootOwner: rootOwnerByValueId.get(row.id) ?? null,
150146
+ thisClassForMember: (member) => thisClassForMember(document, rootOwnerByValueId.get(row.id), member.id),
150089
150147
  compilationProject: compilationProjectFor(document)
150090
150148
  });
150091
150149
  const ownershipIds = (valueId) => ({
@@ -159758,6 +159816,21 @@ var init_client_commit_preparation = __esm({
159758
159816
  }
159759
159817
  });
159760
159818
 
159819
+ // ../src/models/members/animation-child-binding-id.ts
159820
+ function pendingAnimationChildBindingMemberId(classId) {
159821
+ return `${PREFIX}${encodeURIComponent(classId)}`;
159822
+ }
159823
+ function pendingAnimationChildBindingClassId(token) {
159824
+ return token.startsWith(PREFIX) ? decodeURIComponent(token.slice(PREFIX.length)) : null;
159825
+ }
159826
+ var PREFIX;
159827
+ var init_animation_child_binding_id = __esm({
159828
+ "../src/models/members/animation-child-binding-id.ts"() {
159829
+ "use strict";
159830
+ PREFIX = "__pending__:animation-child-binding:";
159831
+ }
159832
+ });
159833
+
159761
159834
  // src/project-source/trusted-commit-verification.ts
159762
159835
  function verifyProjectSourceCommitAgainstStateV4(args) {
159763
159836
  const root = "/neo-source-verify-virtual";
@@ -159956,6 +160029,14 @@ function validateAssignments(value) {
159956
160029
  return assignments;
159957
160030
  }
159958
160031
  function derivedAssignment(pendingId2) {
160032
+ const animationClass = pendingAnimationChildBindingClassId(pendingId2);
160033
+ if (animationClass !== null)
160034
+ return {
160035
+ ownerLocator: animationClass,
160036
+ derive: worldAnimationChildOverrideBindingMemberId,
160037
+ label: "Animation child binding assignment",
160038
+ ownerNoun: "class"
160039
+ };
159959
160040
  const genericArgument = pendingGenericArgumentIdentity(pendingId2);
159960
160041
  if (genericArgument !== null)
159961
160042
  return {
@@ -160079,6 +160160,10 @@ function relocatedAssignment(pendingId2, assignments, byPosition, used) {
160079
160160
  return assignments.has(rebuilt) ? rebuilt : null;
160080
160161
  }
160081
160162
  for (const [owner, rebuild] of [
160163
+ [
160164
+ pendingAnimationChildBindingClassId(pendingId2),
160165
+ pendingAnimationChildBindingMemberId
160166
+ ],
160082
160167
  [pendingMemberValueMemberId(pendingId2), pendingMemberValueId],
160083
160168
  [pendingEntryMemberDeclaringId(pendingId2), pendingEntryMemberId],
160084
160169
  [
@@ -160408,6 +160493,8 @@ var ProjectSourceCommitVerificationError, ABSENT_DIFFERENCE_VALUE;
160408
160493
  var init_trusted_commit_verification = __esm({
160409
160494
  "src/project-source/trusted-commit-verification.ts"() {
160410
160495
  "use strict";
160496
+ init_animation_child_binding_id();
160497
+ init_world_system_classes();
160411
160498
  init_tuple_element_member_id();
160412
160499
  init_identity_rewriter();
160413
160500
  init_generic_argument_member_id();
@@ -163352,6 +163439,7 @@ function lowerVariantGraph(context, binding, created) {
163352
163439
  const storedSource = {
163353
163440
  memberId: rootMember.id,
163354
163441
  purpose: "stored",
163442
+ variantTargetClassId: binding.targetClassId,
163355
163443
  initializer: binding.initializer,
163356
163444
  source: binding.source,
163357
163445
  label: binding.label
@@ -164861,12 +164949,11 @@ function constructorArgumentValueSlices(context, authoredSlice) {
164861
164949
  if (cached !== void 0) return cached;
164862
164950
  const expression = initializerExpressionSlice(authoredSlice);
164863
164951
  if (expression === void 0) return [];
164864
- const values = topLevelEntrySlices(expression, "(", ")").map((entry) => {
164865
- const separator = entry.indexOf(":");
164866
- return normalizeInitializerSource(
164867
- separator < 0 ? entry : entry.slice(separator + 1)
164868
- );
164869
- });
164952
+ const values = topLevelEntrySlices(expression, "(", ")").map(
164953
+ (entry) => normalizeInitializerSource(
164954
+ entry.replace(/^[A-Za-z_][A-Za-z0-9_]*\s*:\s*/, "")
164955
+ )
164956
+ );
164870
164957
  context.syntax.arguments.set(authoredSlice, values);
164871
164958
  return values;
164872
164959
  }
@@ -167988,6 +168075,17 @@ function inferAnimationChildOverrideLowerEnvironment(context, schemaClass2, expr
167988
168075
  return inherited;
167989
168076
  }
167990
168077
  const parameter4 = schemaClass2.genericParameters[0];
168078
+ const explicitType = expression.typeArguments?.[0];
168079
+ if (parameter4 !== void 0 && explicitType !== void 0) {
168080
+ const childClass = requiredClassByName(
168081
+ context,
168082
+ astTypeNameV4(explicitType)
168083
+ );
168084
+ return new Map(inherited).set(
168085
+ parameter4.id,
168086
+ inferredGenericClassBinding(childClass.id)
168087
+ );
168088
+ }
167991
168089
  const parameterName = requiredConstructorFirstParameterName(
167992
168090
  context,
167993
168091
  schemaClass2
@@ -168043,8 +168141,8 @@ function animationChildOverrideSeedBindings(context, schemaClass2, environment,
168043
168141
  );
168044
168142
  }
168045
168143
  const existingBinding = environmentBinding ? context.members.get(environmentBinding) : void 0;
168046
- const reservedBindingMemberId = worldAnimationChildOverrideBindingMemberId(classId);
168047
- const bindingMember = existingBinding?.kind === "class" && existingBinding.classId === classId ? existingBinding : context.members.get(reservedBindingMemberId);
168144
+ const reservedBindingMemberId = isPendingId(classId) ? pendingAnimationChildBindingMemberId(classId) : worldAnimationChildOverrideBindingMemberId(classId);
168145
+ const bindingMember = existingBinding?.kind === "class" && existingBinding.classId === classId && existingBinding.name === WORLD_ANIMATION_CHILD_OVERRIDE_BINDING_MEMBER_NAME ? existingBinding : context.members.get(reservedBindingMemberId);
168048
168146
  if (bindingMember !== void 0) {
168049
168147
  if (bindingMember.kind !== "class" || bindingMember.classId !== classId || bindingMember.name !== WORLD_ANIMATION_CHILD_OVERRIDE_BINDING_MEMBER_NAME) {
168050
168148
  throw new Error(
@@ -170018,7 +170116,7 @@ function lowerDelegateValue(context, member, source, expression, authoredSlice)
170018
170116
  const target = methodGroupTarget(
170019
170117
  context,
170020
170118
  expression,
170021
- source.ownerClassId,
170119
+ source.variantTargetClassId !== void 0 && context.classesByName.get("NeoAnimationChildOverride")?.schema.Selector === member.id ? source.variantTargetClassId : source.ownerClassId,
170022
170120
  member.arguments.map((argument2) => argument2.type)
170023
170121
  );
170024
170122
  if ("failure" in target) {
@@ -173337,6 +173435,7 @@ var INFERRED_GENERIC_CLASS_PREFIX, MEMBER_KIND_DICTIONARY2, MEMBER_KIND_LIST2, M
173337
173435
  var init_value_sources = __esm({
173338
173436
  "src/project-source/value-sources.ts"() {
173339
173437
  "use strict";
173438
+ init_animation_child_binding_id();
173340
173439
  init_source_diagnostics();
173341
173440
  init_immutable_json3();
173342
173441
  init_lower_support();
@@ -175003,6 +175102,39 @@ function prospectiveInitializerRecordsV4(args) {
175003
175102
  });
175004
175103
  }
175005
175104
  }
175105
+ const missingBindings = /* @__PURE__ */ new Set();
175106
+ for (const record7 of records3.values()) {
175107
+ if (record7.recordKind !== "value") continue;
175108
+ const stamp = getField(record7.data, "genericBindings");
175109
+ if (!isObjectRecord(stamp)) continue;
175110
+ for (const id2 of Object.values(stamp)) {
175111
+ if (typeof id2 === "string" && !records3.has(`member:${id2}`))
175112
+ missingBindings.add(id2);
175113
+ }
175114
+ }
175115
+ if (missingBindings.size > 0) {
175116
+ for (const record7 of records3.values()) {
175117
+ if (record7.recordKind !== "class") continue;
175118
+ const classId = record7.recordId;
175119
+ const id2 = isPendingId(classId) ? pendingAnimationChildBindingMemberId(classId) : worldAnimationChildOverrideBindingMemberId(classId);
175120
+ if (!missingBindings.has(id2)) continue;
175121
+ records3.set(`member:${id2}`, {
175122
+ recordKind: "member",
175123
+ recordId: id2,
175124
+ contentHash: "local-binding",
175125
+ deleted: false,
175126
+ data: {
175127
+ ...worldAnimationChildOverrideBindingMember(
175128
+ args.workspace.config.projectId,
175129
+ classId
175130
+ ),
175131
+ id: id2,
175132
+ createdAt: 0,
175133
+ updatedAt: 0
175134
+ }
175135
+ });
175136
+ }
175137
+ }
175006
175138
  return records3;
175007
175139
  }
175008
175140
  function setSeedValueRecord(records3, data) {
@@ -175081,6 +175213,8 @@ var cleanRetainedCode, pulledStateDocuments;
175081
175213
  var init_local_initializer_materialization = __esm({
175082
175214
  "src/project-source/local-initializer-materialization.ts"() {
175083
175215
  "use strict";
175216
+ init_animation_child_binding_id();
175217
+ init_world_system_classes();
175084
175218
  init_stored_value_placements();
175085
175219
  init_local_project_file_storage();
175086
175220
  init_immutable_json3();
@@ -185864,7 +185998,7 @@ var init_project_document_cache = __esm({
185864
185998
  init_registry();
185865
185999
  init_project_documents();
185866
186000
  PROJECT_SOURCE_BUILD_CACHE_PATH = ".neo/build/project-source-analysis-v4.json";
185867
- PROJECT_SOURCE_BUILD_CACHE_REVISION = 9;
186001
+ PROJECT_SOURCE_BUILD_CACHE_REVISION = 10;
185868
186002
  analysisCache = /* @__PURE__ */ new Map();
185869
186003
  MAX_CACHED_WORKSPACES = 4;
185870
186004
  parsedWorkspaceDocuments = /* @__PURE__ */ new Map();
@@ -222824,6 +222958,13 @@ function assignPendingIds(changes, authoredValueSeeds, reconstructed3, previousL
222824
222958
  const assign = (pendingId2) => {
222825
222959
  const existing = assigned.get(pendingId2);
222826
222960
  if (existing !== void 0) return existing;
222961
+ const animationClass = pendingAnimationChildBindingClassId(pendingId2);
222962
+ if (animationClass !== null) {
222963
+ const classId = isPendingId(animationClass) ? assign(animationClass) : animationClass;
222964
+ const derived = worldAnimationChildOverrideBindingMemberId(classId);
222965
+ assigned.set(pendingId2, derived);
222966
+ return derived;
222967
+ }
222827
222968
  const genericArgument = pendingGenericArgumentIdentity(pendingId2);
222828
222969
  if (genericArgument !== null) {
222829
222970
  const parent = isPendingId(genericArgument.parentRecordId) ? assign(genericArgument.parentRecordId) : genericArgument.parentRecordId;
@@ -226007,6 +226148,8 @@ var compileNSVoidBody2, compileNSFunction2, compileNSGetter2, compileNSSetter2,
226007
226148
  var init_push = __esm({
226008
226149
  "src/commands/push.ts"() {
226009
226150
  "use strict";
226151
+ init_animation_child_binding_id();
226152
+ init_world_system_classes();
226010
226153
  init_local_project_file_storage();
226011
226154
  init_generic_argument_member_id();
226012
226155
  init_extension_source_preservation();
@@ -241494,7 +241637,7 @@ var releaseWorkspaceLock = () => void 0;
241494
241637
  async function main() {
241495
241638
  const args = parseArgs(process.argv.slice(2));
241496
241639
  if (args.command === "--version") {
241497
- console.log("0.89.9");
241640
+ console.log("0.89.10");
241498
241641
  return;
241499
241642
  }
241500
241643
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
@@ -38627,6 +38627,16 @@ function readVariantSelection(value, label) {
38627
38627
  }
38628
38628
  return { classId, variantId, rowValueId: rowValueId ?? null };
38629
38629
  }
38630
+ function variantConstructorRecord(row, schemaKeys) {
38631
+ const recipe = isLiteralValueContent(row) ? row.constructorArgs : void 0;
38632
+ const result = {};
38633
+ if (recipe == null) return result;
38634
+ for (let index = 0; index < schemaKeys.length; index++) {
38635
+ const argument2 = recipe[`__arg_${index}__`];
38636
+ if (argument2 !== void 0) result[schemaKeys[index]] = argument2;
38637
+ }
38638
+ return result;
38639
+ }
38630
38640
  function resolveVariantGraph(selection, ctx) {
38631
38641
  const variantId = selection.variantId;
38632
38642
  if (variantId === null) {
@@ -38664,20 +38674,14 @@ function resolveVariantGraph(selection, ctx) {
38664
38674
  );
38665
38675
  }
38666
38676
  const effectiveRoot = { ...root };
38667
- const recipe = row.constructorArgs;
38668
- if (typeof recipe === "object" && recipe !== null) {
38669
- const settledVariantSlots = [
38670
- ["Initialize", 0],
38671
- ["Apply", 1],
38672
- ["Overrides", 2],
38673
- ["ChildOverrides", 3]
38674
- ];
38675
- for (const [schemaKey, argumentIndex] of settledVariantSlots) {
38676
- if (effectiveRoot[schemaKey] !== void 0) continue;
38677
- const argument2 = recipe[`__arg_${argumentIndex}__`];
38678
- if (argument2 === void 0 || argument2 === null) continue;
38679
- effectiveRoot[schemaKey] = argument2;
38680
- }
38677
+ const recipe = variantConstructorRecord(row, [
38678
+ "Initialize",
38679
+ "Apply",
38680
+ "Overrides",
38681
+ "ChildOverrides"
38682
+ ]);
38683
+ for (const [key, value] of Object.entries(recipe)) {
38684
+ if (effectiveRoot[key] === void 0) effectiveRoot[key] = value;
38681
38685
  }
38682
38686
  return {
38683
38687
  variantId,
@@ -38772,7 +38776,7 @@ function invokeVariantClosure(args) {
38772
38776
  [DELEGATE_LEXICAL_THIS]: lexicalThis,
38773
38777
  [DELEGATE_LEXICAL_ROOT]: ctx.rootValue
38774
38778
  };
38775
- return invokeDelegateValue(bound, parameters, ctx);
38779
+ return invokeDelegateValue(bound, parameters, ctx, void 0, lexicalThis);
38776
38780
  }
38777
38781
  function writeVariantOverrideSlot(target, schemaKey, value, ctx, answeredValueIds) {
38778
38782
  assertStoredReplayMutableValue(target, ctx, "variant override", schemaKey);
@@ -38968,6 +38972,32 @@ function replacesInterfaceSlotRow(member, target, overrideRow, ctx) {
38968
38972
  if (targetRow === null) return false;
38969
38973
  return classIdForValueRow(targetRow, ctx) !== overrideRow.classId;
38970
38974
  }
38975
+ function readVariantChildOverrideSlot(entryRow, schemaKey, ctx) {
38976
+ const entry = readRowValue(entryRow, ctx);
38977
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry))
38978
+ return null;
38979
+ const classId = classIdForValueRow(entryRow, ctx);
38980
+ const memberId = classId == null ? null : cachedMergedSchemaMemberId(classId, schemaKey, ctx);
38981
+ const member = memberId === null ? null : evalMemberById(ctx.vm, memberId);
38982
+ if (member === null) {
38983
+ throw new NSGetterRuntimeError(
38984
+ `Child override '${entryRow.id}' has no '${schemaKey}' member.`
38985
+ );
38986
+ }
38987
+ const slot = readClassMember({
38988
+ member,
38989
+ schemaKey,
38990
+ record: entry,
38991
+ expandedRecord: () => variantConstructorRecord(entryRow, ["Selector", "Overrides"]),
38992
+ mode: "runtime"
38993
+ });
38994
+ if (slot.kind === "value") return slot.value;
38995
+ if (slot.kind === "declaration") {
38996
+ const result = readDeclarationDefault(member, ctx);
38997
+ return result.matched ? result.value : null;
38998
+ }
38999
+ return null;
39000
+ }
38971
39001
  function applyVariantDeclarativeHalves(instance, graph, ctx, answeredValueIds) {
38972
39002
  applyVariantPartial(
38973
39003
  instance,
@@ -39006,14 +39036,13 @@ function applyVariantDeclarativeHalves(instance, graph, ctx, answeredValueIds) {
39006
39036
  `Variant '${graph.name}' references missing child-override row '${entryId}'.`
39007
39037
  );
39008
39038
  }
39009
- const entry = entryRow.value;
39039
+ const entry = readRowValue(entryRow, ctx);
39010
39040
  if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
39011
39041
  continue;
39012
39042
  }
39013
- const entryRecord = entry;
39014
39043
  const label = `Variant '${graph.name}' child override '${entryId}'`;
39015
39044
  const child = invokeVariantClosure({
39016
- closureValueId: entryRecord.Selector,
39045
+ closureValueId: readVariantChildOverrideSlot(entryRow, "Selector", ctx),
39017
39046
  ctx,
39018
39047
  label: `${label} Selector`,
39019
39048
  lexicalThis: instance,
@@ -39026,7 +39055,7 @@ function applyVariantDeclarativeHalves(instance, graph, ctx, answeredValueIds) {
39026
39055
  }
39027
39056
  applyVariantPartial(
39028
39057
  child,
39029
- entryRecord.Overrides,
39058
+ readVariantChildOverrideSlot(entryRow, "Overrides", ctx),
39030
39059
  ctx,
39031
39060
  label,
39032
39061
  answeredValueIds
@@ -39148,7 +39177,7 @@ function collectVariantDeclarativeAnsweredSlots(instance, graph, ctx) {
39148
39177
  }
39149
39178
  const label = `Variant '${graph.name}' child override '${entryId}'`;
39150
39179
  const child = invokeVariantClosure({
39151
- closureValueId: Reflect.get(entryRow.value, "Selector"),
39180
+ closureValueId: readVariantChildOverrideSlot(entryRow, "Selector", ctx),
39152
39181
  ctx,
39153
39182
  label: `${label} Selector`,
39154
39183
  lexicalThis: instance,
@@ -39161,7 +39190,7 @@ function collectVariantDeclarativeAnsweredSlots(instance, graph, ctx) {
39161
39190
  }
39162
39191
  collectVariantPartialAnsweredSlots(
39163
39192
  child,
39164
- Reflect.get(entryRow.value, "Overrides"),
39193
+ readVariantChildOverrideSlot(entryRow, "Overrides", ctx),
39165
39194
  ctx,
39166
39195
  label,
39167
39196
  slots
@@ -71707,7 +71736,7 @@ function resolveAnalyzerMember(context, member) {
71707
71736
  }
71708
71737
 
71709
71738
  // ../src/runtime/neoscript/neoscript-language-context-adapter.ts
71710
- var NEOSCRIPT_COMPILER_ADAPTER_REVISION = 7;
71739
+ var NEOSCRIPT_COMPILER_ADAPTER_REVISION = 8;
71711
71740
  var UNKNOWN_TYPE = {
71712
71741
  kind: "primitive",
71713
71742
  name: "unknown"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.89.9",
3
+ "version": "0.89.10",
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.89.9 -->
12
+ <!-- reviewed-through-cli: 0.89.10 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -143,7 +143,7 @@ The marker near the top of `SKILL.md` must exactly match the package version,
143
143
  and this quoted copy is checked too:
144
144
 
145
145
  ```html
146
- <!-- reviewed-through-cli: 0.89.9 -->
146
+ <!-- reviewed-through-cli: 0.89.10 -->
147
147
  ```
148
148
 
149
149
  Keep this skill on current behavior. Upgrade steps, rollout prerequisites,
@@ -25,6 +25,29 @@ NeoVariant<ExampleObject> Down = new(
25
25
  written `new { ... }` or `new Partial<T> { ... }`. They never pass
26
26
  constructor arguments, even when `T` has a required constructor.
27
27
 
28
+ A child override's explicit `NeoAnimationChildOverride<TChild>` argument
29
+ selects the child type and its `Partial<TChild>` payload. The child type may
30
+ extend `NeoObjectBase`; it does not have to equal the list's base type.
31
+ Returning a local variable from the selector preserves that explicit type.
32
+ The selector takes no parameters. Its `this` is the variant target instance,
33
+ so `() => this.SelectFirstSprite()` and `this.SelectFirstSprite` both work
34
+ when that method takes no arguments and returns `TChild`. A search through
35
+ `Children` returns an optional `NeoObjectBase`; narrow it to `TChild` and
36
+ handle the missing-child case before returning it.
37
+
38
+ ```neo
39
+ new NeoAnimationChildOverride<AnimationSpriteObject>(() => {
40
+ if (this.Children.FirstOrDefault((child) => child.Name == "Sprite")
41
+ is not AnimationSpriteObject sprite) {
42
+ throw new NeoError("Expected a sprite child");
43
+ }
44
+ return sprite;
45
+ }, new Partial<AnimationSpriteObject> { Sprite = Images.OreVeins.Slice(1) })
46
+ ```
47
+
48
+ VSCode and `neo status` validate selector bodies and constructor delegate
49
+ arguments, including names, parameter counts, return paths, and return types.
50
+
28
51
  A nested class partial changes only named members. A list override replaces
29
52
  the whole list; it does not patch entries by index. In particular, overriding
30
53
  a clip's `Frames` requires the complete desired list, not just the changed