@neocompose/cli 0.21.3 → 0.21.5

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,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.21.5] - 2026-08-03
4
+
5
+ ### Fixed
6
+
7
+ - Non-empty `neo push` rehearsals compile only the code-only member defaults
8
+ actually reached by canonical constructor replay, so stored animation graphs
9
+ no longer fail on dependencies such as `Down` that correctly omit derived IR
10
+ from the trusted source bundle.
11
+
12
+ ## [0.21.4] - 2026-08-03
13
+
14
+ ### Fixed
15
+
16
+ - `neo pull --reset` emits the canonical `SpriteInfo.Empty` spelling for the
17
+ required empty-sprite sentinel and does not mistake its empty file id for a
18
+ missing project file.
19
+ - Parameterized declaration templates compile with their class-header scope
20
+ without being evaluated before a concrete invocation supplies arguments.
21
+ - Canonical lowering reuses persisted generic argument identities, so a fresh
22
+ reset remains a semantic no-op instead of creating replacement binding rows.
23
+
3
24
  ## [0.21.3] - 2026-08-03
4
25
 
5
26
  ### Fixed
package/dist/neo.mjs CHANGED
@@ -9045,7 +9045,8 @@ var init_strict_resolver = __esm({
9045
9045
  );
9046
9046
  case "call":
9047
9047
  if (expression.callee.kind === "ident" && expression.callee.name === "Reference" && Array.isArray(expression.typeArguments)) {
9048
- if (expression.typeArguments.length !== 1) {
9048
+ const [referenceTypeArgument] = expression.typeArguments;
9049
+ if (expression.typeArguments.length !== 1 || referenceTypeArgument === void 0) {
9049
9050
  throw new CompileError(
9050
9051
  "Reference requires exactly one generic target type.",
9051
9052
  expression.pos
@@ -9057,7 +9058,7 @@ var init_strict_resolver = __esm({
9057
9058
  expression.pos
9058
9059
  );
9059
9060
  }
9060
- const referencedType = this.resolveType(expression.typeArguments[0]);
9061
+ const referencedType = this.resolveType(referenceTypeArgument);
9061
9062
  if (expected !== void 0 && !isNeoScriptTypeAssignable(referencedType, expected, this.project)) {
9062
9063
  throw new CompileError(
9063
9064
  `Reference target ${this.describe(referencedType)} is not assignable to ${this.describe(expected)}.`,
@@ -9111,7 +9112,7 @@ var init_strict_resolver = __esm({
9111
9112
  if (requiredConstructor === null && !callMatchesDeclaredOverloadNames(declared, expression)) {
9112
9113
  this.rejectConstructorProjectionInConstructionBody(expression);
9113
9114
  }
9114
- const projectionCall = requiredConstructor === null && expression.argumentNames === void 0 && callHasPositionalArguments(expression) && declaredTarget?.constructorSignature !== void 0;
9115
+ const projectionCall = requiredConstructor === null && declaredTarget?.constructorSignature !== void 0 && (expression.argumentNames === void 0 && callHasPositionalArguments(expression) || expression.argumentNames !== void 0 && declaredTarget.constructorSignature.namedProjections !== void 0);
9115
9116
  if (declared.length > 0 && !projectionCall) {
9116
9117
  return this.resolveDeclaredConstructor(
9117
9118
  className,
@@ -9120,13 +9121,13 @@ var init_strict_resolver = __esm({
9120
9121
  expression.pos
9121
9122
  );
9122
9123
  }
9123
- if (expression.argumentNames) {
9124
+ if (expression.argumentNames && !projectionCall) {
9124
9125
  throw new CompileError(
9125
9126
  "Named constructor arguments require a declaration-aware project source context.",
9126
9127
  expression.pos
9127
9128
  );
9128
9129
  }
9129
- if (expression.initializer && expression.initializer.length > 0) {
9130
+ if (expression.initializer && expression.initializer.length > 0 && !projectionCall) {
9130
9131
  throw new CompileError(
9131
9132
  "Object initializers are available to project source construction and are not executable NeoScript constructors.",
9132
9133
  expression.pos
@@ -9134,9 +9135,10 @@ var init_strict_resolver = __esm({
9134
9135
  }
9135
9136
  return this.resolveClassConstructor(
9136
9137
  className,
9137
- expression.args,
9138
+ expression,
9138
9139
  scope,
9139
- expression.pos
9140
+ expression.pos,
9141
+ expected
9140
9142
  );
9141
9143
  }
9142
9144
  case "annotated":
@@ -10544,7 +10546,7 @@ var init_strict_resolver = __esm({
10544
10546
  type: optional ? { ...delegateType.returnType, nullable: true } : delegateType.returnType
10545
10547
  };
10546
10548
  }
10547
- resolveClassConstructor(className, argumentsList2, scope, pos) {
10549
+ resolveClassConstructor(className, expression, scope, pos, expected) {
10548
10550
  const schemaClass2 = this.project.typeByName.get(className);
10549
10551
  if (!schemaClass2 || schemaClass2.kind !== "class") {
10550
10552
  throw new CompileError(
@@ -10566,26 +10568,86 @@ var init_strict_resolver = __esm({
10566
10568
  pos
10567
10569
  );
10568
10570
  }
10571
+ const targetType = this.constructorTargetType(
10572
+ schemaClass2,
10573
+ expression,
10574
+ expected
10575
+ );
10576
+ const parameters = signature.parameters.map((parameter3) => ({
10577
+ ...parameter3,
10578
+ valueType: substituteTypeParameters(
10579
+ parameter3.valueType,
10580
+ targetType,
10581
+ schemaClass2
10582
+ ),
10583
+ parameterType: substituteTypeParameters(
10584
+ parameter3.parameterType,
10585
+ targetType,
10586
+ schemaClass2
10587
+ )
10588
+ }));
10589
+ const argumentsList2 = expression.args;
10590
+ const namedProjections = signature.namedProjections;
10591
+ if (expression.argumentNames !== void 0) {
10592
+ if (namedProjections === void 0) {
10593
+ throw new CompileError(
10594
+ `Class '${className}' exposes no named constructor projection.`,
10595
+ pos
10596
+ );
10597
+ }
10598
+ if (argumentsList2.length !== namedProjections.length) {
10599
+ throw new CompileError(
10600
+ `${className} constructor requires ${namedProjections.length} named argument${namedProjections.length === 1 ? "" : "s"} but got ${argumentsList2.length}.`,
10601
+ pos
10602
+ );
10603
+ }
10604
+ if (expression.argumentNames.length !== argumentsList2.length) {
10605
+ throw new CompileError(
10606
+ `${className} constructor projection requires every argument to be named.`,
10607
+ pos
10608
+ );
10609
+ }
10610
+ }
10569
10611
  const requiredCount = signature.parameters.filter(
10570
10612
  (parameter3) => parameter3.required
10571
10613
  ).length;
10572
- if (argumentsList2.length < requiredCount) {
10614
+ if (expression.argumentNames === void 0 && argumentsList2.length < requiredCount) {
10573
10615
  throw new CompileError(
10574
10616
  `${className} constructor requires ${requiredCount} argument${requiredCount === 1 ? "" : "s"} but got ${argumentsList2.length}.`,
10575
10617
  pos
10576
10618
  );
10577
10619
  }
10578
- if (argumentsList2.length > signature.parameters.length) {
10620
+ if (expression.argumentNames === void 0 && argumentsList2.length > parameters.length) {
10579
10621
  throw new CompileError(
10580
- `${className} constructor accepts at most ${signature.parameters.length} argument${signature.parameters.length === 1 ? "" : "s"} but got ${argumentsList2.length}.`,
10622
+ `${className} constructor accepts at most ${parameters.length} argument${parameters.length === 1 ? "" : "s"} but got ${argumentsList2.length}.`,
10581
10623
  pos
10582
10624
  );
10583
10625
  }
10584
10626
  const fields = argumentsList2.map((argument2, index) => {
10585
- const parameter3 = signature.parameters[index];
10627
+ const projectionName = expression.argumentNames?.[index];
10628
+ const projection = projectionName === void 0 ? void 0 : namedProjections?.find(
10629
+ (candidate) => candidate.name === projectionName
10630
+ );
10631
+ if (projectionName !== void 0 && projection === void 0) {
10632
+ throw new CompileError(
10633
+ `Class '${className}' has no constructor projection named '${projectionName}'.`,
10634
+ argument2.pos
10635
+ );
10636
+ }
10637
+ if (projection !== void 0 && expression.argumentNames?.findIndex(
10638
+ (candidate) => candidate === projection.name
10639
+ ) !== index) {
10640
+ throw new CompileError(
10641
+ `Constructor argument '${projection.name}' is supplied more than once.`,
10642
+ argument2.pos
10643
+ );
10644
+ }
10645
+ const parameter3 = projection === void 0 ? parameters[index] : parameters.find(
10646
+ (candidate) => candidate.memberId === projection.memberId
10647
+ );
10586
10648
  if (!parameter3) {
10587
10649
  throw new Error(
10588
- `NeoScript constructor ${className} lost parameter ${index + 1} after argument-count validation.`
10650
+ projection === void 0 ? `NeoScript constructor ${className} lost parameter ${index + 1} after argument-count validation.` : `NeoScript constructor ${className} projection '${projection.name}' names missing member '${projection.memberId}'.`
10589
10651
  );
10590
10652
  }
10591
10653
  const value = this.resolveExpression(
@@ -10605,7 +10667,20 @@ var init_strict_resolver = __esm({
10605
10667
  valuePointer: value.pointer
10606
10668
  };
10607
10669
  });
10608
- const schemaClassInfo = toWireType(signature.returnType, this.project);
10670
+ if (namedProjections !== void 0 && expression.argumentNames !== void 0) {
10671
+ for (const projection of namedProjections) {
10672
+ if (!expression.argumentNames.includes(projection.name)) {
10673
+ throw new CompileError(
10674
+ `${className} constructor is missing named argument '${projection.name}'.`,
10675
+ pos
10676
+ );
10677
+ }
10678
+ }
10679
+ }
10680
+ fields.push(
10681
+ ...this.resolveCallSiteInitializerFields(schemaClass2, expression, scope)
10682
+ );
10683
+ const schemaClassInfo = toWireType(targetType, this.project);
10609
10684
  if (schemaClassInfo.type !== 7 /* Class */) {
10610
10685
  throw new Error(
10611
10686
  `NeoScript constructor ${className} has non-Class return type ${this.describe(signature.returnType)}.`
@@ -10619,10 +10694,35 @@ var init_strict_resolver = __esm({
10619
10694
  info: { schemaClassInfo, fields }
10620
10695
  }
10621
10696
  },
10622
- type: { ...signature.returnType, nullable: false },
10697
+ type: { ...targetType, nullable: false },
10623
10698
  writability: "session" /* Session */
10624
10699
  };
10625
10700
  }
10701
+ constructorTargetType(schemaClass2, expression, expected) {
10702
+ const typeArguments = expression.typeArguments?.map(
10703
+ (argument2) => this.resolveType(argument2)
10704
+ );
10705
+ if (typeArguments !== void 0 && typeArguments.length !== (schemaClass2.typeParameters?.length ?? 0)) {
10706
+ throw new CompileError(
10707
+ `Class '${schemaClass2.name}' expects ${schemaClass2.typeParameters?.length ?? 0} type argument${schemaClass2.typeParameters?.length === 1 ? "" : "s"} but got ${typeArguments.length}.`,
10708
+ expression.pos
10709
+ );
10710
+ }
10711
+ if (typeArguments !== void 0) {
10712
+ return {
10713
+ kind: "named",
10714
+ typeId: schemaClass2.id,
10715
+ typeArguments
10716
+ };
10717
+ }
10718
+ if (expected?.kind === "named" && expected.typeId === schemaClass2.id) {
10719
+ return { ...expected, nullable: false };
10720
+ }
10721
+ return {
10722
+ kind: "named",
10723
+ typeId: schemaClass2.id
10724
+ };
10725
+ }
10626
10726
  /**
10627
10727
  * P43 §7.1. P29's `new T(id: "…")` projection names a class-default row,
10628
10728
  * which is exactly the wrong identity inside a construction body: member
@@ -44500,7 +44600,13 @@ function lowerFieldMember(context, ownerClass, declaration, id2, commonInput, ba
44500
44600
  classId,
44501
44601
  ...partial ? { partial: true } : {},
44502
44602
  schemaKeyOrder: base?.kind === "class" ? base.schemaKeyOrder : null,
44503
- classArguments: lowerClassArguments(context, ownerClass, id2, fieldType)
44603
+ classArguments: lowerClassArguments(
44604
+ context,
44605
+ ownerClass,
44606
+ id2,
44607
+ fieldType,
44608
+ base?.kind === "class" ? base.classArguments : void 0
44609
+ )
44504
44610
  };
44505
44611
  }
44506
44612
  throw new Error(
@@ -45575,7 +45681,7 @@ function genericParameterName(context, genericParamId) {
45575
45681
  }
45576
45682
  return "object";
45577
45683
  }
45578
- function lowerClassArguments(context, ownerClass, ownerMemberId, type) {
45684
+ function lowerClassArguments(context, ownerClass, ownerMemberId, type, baseArguments) {
45579
45685
  const classId = context.classIdsByName.get(type.name);
45580
45686
  if (!classId) return {};
45581
45687
  const parameters = [
@@ -45591,7 +45697,8 @@ function lowerClassArguments(context, ownerClass, ownerMemberId, type) {
45591
45697
  result[parameterId] = { kind: "generic", genericParamId: ownerParameter };
45592
45698
  continue;
45593
45699
  }
45594
- const memberId = derivedGenericArgumentMemberId(ownerMemberId, parameterId);
45700
+ const baseBinding = baseArguments?.[parameterId];
45701
+ const memberId = baseBinding?.kind === "member" ? baseBinding.memberId : derivedGenericArgumentMemberId(ownerMemberId, parameterId);
45595
45702
  result[parameterId] = { kind: "member", memberId };
45596
45703
  lowerGenericArgument(
45597
45704
  context,
@@ -45611,6 +45718,7 @@ function lowerExtendsBindings(context, declaration, baseClassId, argumentsValue)
45611
45718
  ];
45612
45719
  const result = {};
45613
45720
  const declarationId = materializedId(declaration, "class", declaration.name);
45721
+ const baseBindings = context.baseClasses.get(declarationId)?.extendsGenericBindings ?? {};
45614
45722
  for (const [[parameterName, parameterId], argumentType] of zip(
45615
45723
  parameters,
45616
45724
  argumentsValue
@@ -45620,7 +45728,8 @@ function lowerExtendsBindings(context, declaration, baseClassId, argumentsValue)
45620
45728
  result[parameterId] = { kind: "generic", genericParamId: local };
45621
45729
  continue;
45622
45730
  }
45623
- const memberId = derivedGenericArgumentMemberId(declarationId, parameterId);
45731
+ const baseBinding = baseBindings[parameterId];
45732
+ const memberId = baseBinding?.kind === "member" ? baseBinding.memberId : derivedGenericArgumentMemberId(declarationId, parameterId);
45624
45733
  result[parameterId] = { kind: "member", memberId };
45625
45734
  lowerGenericArgument(
45626
45735
  context,
@@ -47646,6 +47755,15 @@ function renderDefaultValue(context, member, wrapper) {
47646
47755
  `${member.kind === "sprite" ? "Sprite" : "Audio"} member ${JSON.stringify(member.name)} default stores a file value with no fileId. Emitting it as null would delete the default on the next push.`
47647
47756
  );
47648
47757
  }
47758
+ if (value.fileId.length === 0) {
47759
+ const sliceIndex = typeof value.sliceIndex === "number" ? value.sliceIndex : 0;
47760
+ if (member.kind === "sprite" && sliceIndex === 0) {
47761
+ return "SpriteInfo.Empty";
47762
+ }
47763
+ throw new Error(
47764
+ `${member.kind === "sprite" ? "Sprite" : "Audio"} member ${JSON.stringify(member.name)} default stores an invalid empty file value.`
47765
+ );
47766
+ }
47649
47767
  const symbol = context.fileSymbols.get(value.fileId);
47650
47768
  const target = symbol ?? (member.kind === "sprite" ? `Reference<NeoImage>(id: ${quote(value.fileId)})` : `Reference<NeoAudioClip>(id: ${quote(value.fileId)})`);
47651
47769
  return member.kind === "sprite" ? `${target}.Slice(${typeof value.sliceIndex === "number" ? value.sliceIndex : 0})` : target;
@@ -48582,6 +48700,7 @@ function validateFinalizedFileAssignmentsV4(records2, options = {}) {
48582
48700
  return;
48583
48701
  }
48584
48702
  if (!isObjectRecord2(value)) return;
48703
+ if (isEmptySpriteValue(value)) return;
48585
48704
  if (isStructuredLeafPartialValue(value)) {
48586
48705
  visitSpriteFileField(
48587
48706
  value[STRUCTURED_LEAF_PARTIAL_KEY].fileId,
@@ -52582,7 +52701,10 @@ function classToLanguageType(schemaClass2, context) {
52582
52701
  }
52583
52702
  function constructorSignature(schemaClass2, members, context, genericEnvironment) {
52584
52703
  if (schemaClass2.isAbstract) return {};
52585
- if (!isClosedClass(schemaClass2.id, context.vm.classes)) return {};
52704
+ const projections = inheritedConstructorProjections(schemaClass2, context);
52705
+ if (projections.length === 0 && !isClosedClass(schemaClass2.id, context.vm.classes)) {
52706
+ return {};
52707
+ }
52586
52708
  if (resolveAllowedStorage(schemaClass2.id, context.vm.classes) === "immutable" /* Immutable */) {
52587
52709
  return { constructorUnavailableReason: "immutableOnly" };
52588
52710
  }
@@ -52603,11 +52725,43 @@ function constructorSignature(schemaClass2, members, context, genericEnvironment
52603
52725
  defaultValue: "defaultValue" in resolved ? resolved.defaultValue : void 0
52604
52726
  };
52605
52727
  } catch {
52728
+ if (projections.some((projection) => projection.memberId === memberId)) {
52729
+ return { required: true };
52730
+ }
52606
52731
  return null;
52607
52732
  }
52608
52733
  }
52609
52734
  );
52610
- return { constructorSignature: signature };
52735
+ return {
52736
+ constructorSignature: {
52737
+ ...signature,
52738
+ ...projections.length === 0 ? {} : {
52739
+ namedProjections: projections.map((projection) => ({
52740
+ name: projection.parameterName,
52741
+ memberId: projection.memberId
52742
+ }))
52743
+ }
52744
+ }
52745
+ };
52746
+ }
52747
+ function inheritedConstructorProjections(schemaClass2, context) {
52748
+ const classesById = new Map(
52749
+ context.vm.classes.map((candidate) => [candidate.id, candidate])
52750
+ );
52751
+ const projections = [];
52752
+ const claimed = /* @__PURE__ */ new Set();
52753
+ const visited = /* @__PURE__ */ new Set();
52754
+ let current = schemaClass2;
52755
+ while (current !== void 0 && !visited.has(current.id)) {
52756
+ visited.add(current.id);
52757
+ for (const projection of current.constructorProjections ?? []) {
52758
+ if (claimed.has(projection.parameterName)) continue;
52759
+ claimed.add(projection.parameterName);
52760
+ projections.push(projection);
52761
+ }
52762
+ current = current.extendsClassId ? classesById.get(current.extendsClassId) : void 0;
52763
+ }
52764
+ return projections;
52611
52765
  }
52612
52766
  function declaredConstructors(schemaClass2, context) {
52613
52767
  const requiredConstructorId2 = schemaClass2.requiredConstructorId;
@@ -54316,13 +54470,37 @@ function throwNamedBodyCompileFailure(args) {
54316
54470
  });
54317
54471
  }
54318
54472
  function resolveMemberDeclaredTypeInfo(member, members) {
54473
+ return resolveMemberDeclaredTypeInfoInternal(member, members, /* @__PURE__ */ new Set());
54474
+ }
54475
+ function resolveMemberDeclaredTypeInfoInternal(member, members, seen) {
54319
54476
  const resolved = resolveMember2(member, members);
54477
+ const memberId = getField(resolved, "id");
54478
+ if (typeof memberId === "string" && seen.has(memberId)) return null;
54479
+ const nextSeen = typeof memberId === "string" ? /* @__PURE__ */ new Set([...seen, memberId]) : new Set(seen);
54320
54480
  if (isMemberNSPropertyBase(resolved)) return resolved.returnTypeInfo;
54321
54481
  if (isMemberClassBase(resolved)) {
54482
+ const typeArguments = Object.fromEntries(
54483
+ Object.entries(resolved.classArguments ?? {}).flatMap(
54484
+ ([genericParamId, binding]) => {
54485
+ if (binding.kind !== "member") return [];
54486
+ const argumentMember = members.find(
54487
+ (candidate) => candidate.id === binding.memberId
54488
+ );
54489
+ if (argumentMember === void 0) return [];
54490
+ const argumentType = resolveMemberDeclaredTypeInfoInternal(
54491
+ argumentMember,
54492
+ members,
54493
+ nextSeen
54494
+ );
54495
+ return argumentType === null ? [] : [[genericParamId, { ...argumentType, required: true }]];
54496
+ }
54497
+ )
54498
+ );
54322
54499
  return {
54323
54500
  type: 7 /* Class */,
54324
54501
  required: resolved.required,
54325
- classId: resolved.classId
54502
+ classId: resolved.classId,
54503
+ ...Object.keys(typeArguments).length === 0 ? {} : { typeArguments }
54326
54504
  };
54327
54505
  }
54328
54506
  if (isMemberEnumBase(resolved)) {
@@ -54349,7 +54527,11 @@ function resolveMemberDeclaredTypeInfo(member, members) {
54349
54527
  (candidate) => candidate.id === resolved.entryMemberId
54350
54528
  );
54351
54529
  if (entry === void 0) return null;
54352
- const entryTypeInfo = resolveMemberDeclaredTypeInfo(entry, members);
54530
+ const entryTypeInfo = resolveMemberDeclaredTypeInfoInternal(
54531
+ entry,
54532
+ members,
54533
+ nextSeen
54534
+ );
54353
54535
  if (entryTypeInfo === null) return null;
54354
54536
  return {
54355
54537
  type: resolved.kind,
@@ -54365,7 +54547,7 @@ function resolveMemberDeclaredTypeInfo(member, members) {
54365
54547
  if (collection === void 0) return null;
54366
54548
  return lookupDeclaredTypeInfo(
54367
54549
  resolved,
54368
- resolveMemberDeclaredTypeInfo(collection, members)
54550
+ resolveMemberDeclaredTypeInfoInternal(collection, members, nextSeen)
54369
54551
  );
54370
54552
  }
54371
54553
  if (!memberKindSupportsStorage(resolved.kind)) return null;
@@ -55230,7 +55412,7 @@ var init_constructor_argument_ownership = __esm({
55230
55412
  });
55231
55413
 
55232
55414
  // ../src/view-models/neoscript-evaluator/NSGetterRuntimeError.ts
55233
- var NSGetterRuntimeError;
55415
+ var NSGetterRuntimeError, UncompiledInitializerRuntimeError;
55234
55416
  var init_NSGetterRuntimeError = __esm({
55235
55417
  "../src/view-models/neoscript-evaluator/NSGetterRuntimeError.ts"() {
55236
55418
  "use strict";
@@ -55240,6 +55422,16 @@ var init_NSGetterRuntimeError = __esm({
55240
55422
  this.name = "NSGetterRuntimeError";
55241
55423
  }
55242
55424
  };
55425
+ UncompiledInitializerRuntimeError = class extends NSGetterRuntimeError {
55426
+ constructor(memberId, memberName) {
55427
+ super(
55428
+ `Initializer for '${memberName}' has no compiled body; push the project so the server compiles it.`
55429
+ );
55430
+ this.memberId = memberId;
55431
+ this.name = "UncompiledInitializerRuntimeError";
55432
+ }
55433
+ memberId;
55434
+ };
55243
55435
  }
55244
55436
  });
55245
55437
 
@@ -56162,7 +56354,7 @@ var init_project2 = __esm({
56162
56354
 
56163
56355
  // ../src/view-models/neoscript-evaluator/evaluateNSGetter.ts
56164
56356
  function isCatchableNSRuntimeError(error) {
56165
- return error instanceof NSGetterRuntimeError && !(error instanceof NonCatchableNSGetterRuntimeError);
56357
+ return error instanceof NSGetterRuntimeError && !(error instanceof UncompiledInitializerRuntimeError) && !(error instanceof NonCatchableNSGetterRuntimeError);
56166
56358
  }
56167
56359
  function makeEvaluatorLookups(members, values, options = {}) {
56168
56360
  const attrMap = /* @__PURE__ */ new Map();
@@ -60912,8 +61104,10 @@ function evaluateInitializerInContext(init, member, ctx, createdValues, argument
60912
61104
  ctx.__constructedArgumentsByValue ??= /* @__PURE__ */ new WeakMap();
60913
61105
  const compiled = init.compiled;
60914
61106
  if (compiled === void 0) {
60915
- throw new NSGetterRuntimeError(
60916
- `Initializer for '${member.name}' has no compiled body; push the project so the server compiles it.`
61107
+ const memberId = Reflect.get(member, "id");
61108
+ throw new UncompiledInitializerRuntimeError(
61109
+ typeof memberId === "string" ? memberId : null,
61110
+ member.name
60917
61111
  );
60918
61112
  }
60919
61113
  const closeFrame = pushConstructionFrame(ctx, `${member.name} initializer`);
@@ -62343,8 +62537,9 @@ function buildInitializerRootValue(document) {
62343
62537
  function evaluateMemberInitializer(args) {
62344
62538
  const compiled = args.init.compiled;
62345
62539
  if (compiled === void 0) {
62346
- throw new NSGetterRuntimeError(
62347
- `Initializer for '${args.member.name}' has no compiled body; push the project so the server compiles it.`
62540
+ throw new UncompiledInitializerRuntimeError(
62541
+ typeof Reflect.get(args.member, "id") === "string" ? Reflect.get(args.member, "id") : null,
62542
+ args.member.name
62348
62543
  );
62349
62544
  }
62350
62545
  const ctx = {
@@ -75250,24 +75445,7 @@ var init_server_preparation_preflight = __esm({
75250
75445
  function replayStoredConstructionV4(args) {
75251
75446
  const document = args.document ?? readPulledProjectDocumentV4(args.records);
75252
75447
  if (args.compileDocumentBodies === true) {
75253
- const compileArgs = {
75254
- project: document.project,
75255
- projectFiles: document.projectFiles,
75256
- members: document.members,
75257
- classes: document.classes,
75258
- enums: document.enums,
75259
- interfaces: document.interfaces,
75260
- constructors: document.constructors ?? []
75261
- };
75262
- for (const constructor2 of compileArgs.constructors) {
75263
- compileConstructorRecord({ ...compileArgs, constructor: constructor2 });
75264
- }
75265
- for (const member of compileArgs.members) {
75266
- const thisClass = compileArgs.classes.find(
75267
- (schemaClass2) => Object.values(schemaClass2.schema).includes(member.id)
75268
- ) ?? null;
75269
- compileAuthoredMemberBodies({ ...compileArgs, member, thisClass });
75270
- }
75448
+ compilePulledProjectDocumentBodiesV4(document);
75271
75449
  }
75272
75450
  const root = document.values.find((value) => value.id === args.valueId);
75273
75451
  if (root === void 0) {
@@ -75316,22 +75494,36 @@ function replayStoredConstructionV4(args) {
75316
75494
  member: compileMember,
75317
75495
  valueRow: candidate,
75318
75496
  valueId: args.valueId,
75319
- // P61 instance calls are self-contained and never inherit a declaration's
75320
- // required-constructor parameter envelope.
75321
- initializerOwnerClass: null
75497
+ // Instance calls are self-contained. Declaration calls inherit the class
75498
+ // header parameters that are in lexical scope at their source site.
75499
+ initializerOwnerClass: args.initializerOwnerClass ?? null
75322
75500
  });
75323
75501
  if (!isMemberValue(candidate) || !isInitValueContent(candidate)) {
75324
75502
  throw new Error(
75325
75503
  `Construction replay for value "${args.valueId}" did not compile an initializer row.`
75326
75504
  );
75327
75505
  }
75328
- const materialized = materializeInitializerValue({
75329
- document,
75330
- // Constructor-only rows have no structural member owner. Use the same
75331
- // explicit typed descriptor for evaluation that compiled the replay.
75332
- member: compileMember,
75333
- row: candidate
75334
- });
75506
+ if (args.evaluate === false) return /* @__PURE__ */ new Map();
75507
+ const compiledDependencies = /* @__PURE__ */ new Set();
75508
+ let materialized;
75509
+ for (; ; ) {
75510
+ try {
75511
+ materialized = materializeInitializerValue({
75512
+ document,
75513
+ // Constructor-only rows have no structural member owner. Use the same
75514
+ // explicit typed descriptor for evaluation that compiled the replay.
75515
+ member: compileMember,
75516
+ row: candidate
75517
+ });
75518
+ break;
75519
+ } catch (error) {
75520
+ if (!(error instanceof UncompiledInitializerRuntimeError) || error.memberId === null || compiledDependencies.has(error.memberId)) {
75521
+ throw error;
75522
+ }
75523
+ compilePulledMemberInitializerBodyV4(document, error.memberId);
75524
+ compiledDependencies.add(error.memberId);
75525
+ }
75526
+ }
75335
75527
  return new Map(
75336
75528
  [materialized.root, ...materialized.createdValues].map((row) => [
75337
75529
  row.id,
@@ -75339,6 +75531,59 @@ function replayStoredConstructionV4(args) {
75339
75531
  ])
75340
75532
  );
75341
75533
  }
75534
+ function compilePulledProjectDocumentBodiesV4(document) {
75535
+ const compileArgs = {
75536
+ project: document.project,
75537
+ projectFiles: document.projectFiles,
75538
+ members: document.members,
75539
+ classes: document.classes,
75540
+ enums: document.enums,
75541
+ interfaces: document.interfaces,
75542
+ constructors: document.constructors ?? []
75543
+ };
75544
+ for (const constructor2 of compileArgs.constructors) {
75545
+ compileConstructorRecord({ ...compileArgs, constructor: constructor2 });
75546
+ }
75547
+ const ownerClassByMemberId = new Map(
75548
+ compileArgs.classes.flatMap(
75549
+ (schemaClass2) => Object.values(schemaClass2.schema).map(
75550
+ (memberId) => [memberId, schemaClass2]
75551
+ )
75552
+ )
75553
+ );
75554
+ for (const member of compileArgs.members) {
75555
+ compileAuthoredMemberBodies({
75556
+ ...compileArgs,
75557
+ member,
75558
+ thisClass: ownerClassByMemberId.get(member.id) ?? null
75559
+ });
75560
+ }
75561
+ }
75562
+ function compilePulledMemberInitializerBodyV4(document, memberId) {
75563
+ const compileArgs = {
75564
+ project: document.project,
75565
+ projectFiles: document.projectFiles,
75566
+ members: document.members,
75567
+ classes: document.classes,
75568
+ enums: document.enums,
75569
+ interfaces: document.interfaces,
75570
+ constructors: document.constructors ?? []
75571
+ };
75572
+ const member = compileArgs.members.find((entry) => entry.id === memberId);
75573
+ if (member === void 0) {
75574
+ throw new Error(
75575
+ `Cannot compile initializer dependency for missing member "${memberId}".`
75576
+ );
75577
+ }
75578
+ const thisClass = compileArgs.classes.find(
75579
+ (schemaClass2) => Object.values(schemaClass2.schema).includes(memberId)
75580
+ ) ?? null;
75581
+ compileMemberInitializerBody({
75582
+ ...compileArgs,
75583
+ member,
75584
+ thisClass
75585
+ });
75586
+ }
75342
75587
  function readPulledProjectDocumentV4(records2) {
75343
75588
  return readProjectDocument(
75344
75589
  pulledProjectDocumentRaw(replayWorkspace(records2))
@@ -75381,6 +75626,7 @@ var init_initializer_replay = __esm({
75381
75626
  init_project_document_read();
75382
75627
  init_server_preparation_preflight();
75383
75628
  init_projection();
75629
+ init_neoscript_evaluator();
75384
75630
  }
75385
75631
  });
75386
75632
 
@@ -76434,7 +76680,7 @@ function lowerRowBackedDefault(context, member, backed, baseData3, binding) {
76434
76680
  const assignmentSlices = objectInitializerSlices(binding.initializer);
76435
76681
  for (const assignment of expression.initializer ?? []) {
76436
76682
  const childMember = classMemberByName(context, classId, assignment.name);
76437
- if (inheritedConstructorProjections(context.classes, schemaClass2.id).some(
76683
+ if (inheritedConstructorProjections2(context.classes, schemaClass2.id).some(
76438
76684
  (projection) => projection.memberId === childMember.id
76439
76685
  )) {
76440
76686
  throw new Error(
@@ -76847,7 +77093,7 @@ function lowerSeedRow(context, member, sourceExpression, source, valueId, path,
76847
77093
  effectiveClass.id,
76848
77094
  assignment.name
76849
77095
  );
76850
- if (inheritedConstructorProjections(
77096
+ if (inheritedConstructorProjections2(
76851
77097
  context.classes,
76852
77098
  effectiveClass.id
76853
77099
  ).some((projection) => projection.memberId === childMember.id)) {
@@ -77145,15 +77391,17 @@ function lowerValueRow(context, member, sourceExpression, expectedValueId, sourc
77145
77391
  `Value ${expectedValueId} stores constructor arguments but its declared member ${resolvedMember.name} is not a Class.`
77146
77392
  );
77147
77393
  }
77148
- context.initializerReconciliations.set(expectedValueId, {
77149
- valueId: expectedValueId,
77150
- code,
77151
- storedConstructorArgs: storedConstructorArgs === null ? null : structuredClone(storedConstructorArgs),
77152
- settleFields: expression.kind === "new" ? (expression.initializer ?? []).map(
77153
- (assignment) => assignment.name
77154
- ) : [],
77155
- site: referenceSite(source, expression)
77156
- });
77394
+ if (source.purpose === "stored") {
77395
+ context.initializerReconciliations.set(expectedValueId, {
77396
+ valueId: expectedValueId,
77397
+ code,
77398
+ storedConstructorArgs: storedConstructorArgs === null ? null : structuredClone(storedConstructorArgs),
77399
+ settleFields: expression.kind === "new" ? (expression.initializer ?? []).map(
77400
+ (assignment) => assignment.name
77401
+ ) : [],
77402
+ site: referenceSite(source, expression)
77403
+ });
77404
+ }
77157
77405
  const value2 = lowerClassValue(
77158
77406
  context,
77159
77407
  resolvedMember,
@@ -77348,7 +77596,7 @@ function lowerClassValue(context, member, expression, base, source, outerEnviron
77348
77596
  }
77349
77597
  for (const assignment of expression.initializer ?? []) {
77350
77598
  const childMember = classMemberByName(context, classId, assignment.name);
77351
- if (inheritedConstructorProjections(context.classes, schemaClass2.id).some(
77599
+ if (inheritedConstructorProjections2(context.classes, schemaClass2.id).some(
77352
77600
  (projection) => projection.memberId === childMember.id
77353
77601
  )) {
77354
77602
  throw new Error(
@@ -77530,7 +77778,7 @@ function classInheritanceChain(classes, classId) {
77530
77778
  }
77531
77779
  return chain;
77532
77780
  }
77533
- function inheritedConstructorProjections(classes, classId) {
77781
+ function inheritedConstructorProjections2(classes, classId) {
77534
77782
  const resolved = [];
77535
77783
  const claimed = /* @__PURE__ */ new Set();
77536
77784
  for (const schemaClass2 of classInheritanceChain(classes, classId)) {
@@ -77551,7 +77799,7 @@ function inheritedProjectionSchemaKey(classes, classId, memberId) {
77551
77799
  return null;
77552
77800
  }
77553
77801
  function resolveConstructorProjectionArguments(context, schemaClass2, expression, ownerValueId, environment, source) {
77554
- const projections = inheritedConstructorProjections(
77802
+ const projections = inheritedConstructorProjections2(
77555
77803
  context.classes,
77556
77804
  schemaClass2.id
77557
77805
  );
@@ -79856,7 +80104,7 @@ function manifestMemberTypeName(context, member) {
79856
80104
  return fixedSourceTypeNameForKind(member.kind) ?? member.kind;
79857
80105
  }
79858
80106
  function constructorProjectionSource(context, classId, body, visited, environment) {
79859
- const projections = inheritedConstructorProjections(
80107
+ const projections = inheritedConstructorProjections2(
79860
80108
  context.manifestClasses,
79861
80109
  classId
79862
80110
  );
@@ -84019,11 +84267,12 @@ function replayAnimationDeclarationInitializersV4(records2, document) {
84019
84267
  });
84020
84268
  if (initializers.length === 0) return document;
84021
84269
  const rootKinds = /* @__PURE__ */ new Map();
84270
+ const rootOwners = /* @__PURE__ */ new Map();
84022
84271
  const owners = resolveOwnerMembersForValues(
84023
84272
  document,
84024
84273
  new Set(initializers.map(({ row }) => row.id)),
84025
84274
  void 0,
84026
- void 0,
84275
+ rootOwners,
84027
84276
  rootKinds
84028
84277
  );
84029
84278
  const pulled = /* @__PURE__ */ new Map();
@@ -84048,12 +84297,20 @@ function replayAnimationDeclarationInitializersV4(records2, document) {
84048
84297
  if (!classBelongsToAnimationFamily(document.classes, declaredClassId)) {
84049
84298
  continue;
84050
84299
  }
84300
+ const rootOwner = rootOwners.get(row.id);
84301
+ const rootOwnerId = Reflect.get(rootOwner ?? {}, "id");
84302
+ const initializerOwnerClass = typeof rootOwnerId !== "string" ? null : findSchemaPlacement(rootOwnerId, document.classes)?.ownerClass ?? null;
84051
84303
  const replay = replayStoredConstructionV4({
84052
84304
  records: pulled,
84053
84305
  valueId: row.id,
84054
84306
  code,
84055
84307
  member: owner,
84056
- compileDocumentBodies: true
84308
+ compileDocumentBodies: true,
84309
+ initializerOwnerClass,
84310
+ // A parameterized declaration is a template. Its arguments exist only
84311
+ // at concrete construction sites, so validate the authored body here
84312
+ // without fabricating values for the class header parameters.
84313
+ evaluate: initializerOwnerClass?.requiredConstructorId === void 0 || initializerOwnerClass.requiredConstructorId === null
84057
84314
  });
84058
84315
  for (const [id2, value] of replay) {
84059
84316
  if (!isMemberValue(value)) {
@@ -84437,6 +84694,7 @@ var init_workspace_status = __esm({
84437
84694
  init_project_documents();
84438
84695
  init_animation_clips();
84439
84696
  init_classes();
84697
+ init_inheritance();
84440
84698
  init_members();
84441
84699
  init_value_row_owner_members();
84442
84700
  init_project2();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.21.3",
3
+ "version": "0.21.5",
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.21.3 -->
12
+ <!-- reviewed-through-cli: 0.21.5 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -73,7 +73,7 @@ wrappers.
73
73
  The marker near the top of `SKILL.md` must exactly match the package version:
74
74
 
75
75
  ```html
76
- <!-- reviewed-through-cli: 0.21.3 -->
76
+ <!-- reviewed-through-cli: 0.21.5 -->
77
77
  ```
78
78
 
79
79
  The quoted version above is checked too, so this instruction cannot go stale