@neocompose/cli 0.21.3 → 0.21.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.21.4] - 2026-08-03
4
+
5
+ ### Fixed
6
+
7
+ - `neo pull --reset` emits the canonical `SpriteInfo.Empty` spelling for the
8
+ required empty-sprite sentinel and does not mistake its empty file id for a
9
+ missing project file.
10
+ - Parameterized declaration templates compile with their class-header scope
11
+ without being evaluated before a concrete invocation supplies arguments.
12
+ - Canonical lowering reuses persisted generic argument identities, so a fresh
13
+ reset remains a semantic no-op instead of creating replacement binding rows.
14
+
3
15
  ## [0.21.3] - 2026-08-03
4
16
 
5
17
  ### 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;
@@ -75316,15 +75498,16 @@ function replayStoredConstructionV4(args) {
75316
75498
  member: compileMember,
75317
75499
  valueRow: candidate,
75318
75500
  valueId: args.valueId,
75319
- // P61 instance calls are self-contained and never inherit a declaration's
75320
- // required-constructor parameter envelope.
75321
- initializerOwnerClass: null
75501
+ // Instance calls are self-contained. Declaration calls inherit the class
75502
+ // header parameters that are in lexical scope at their source site.
75503
+ initializerOwnerClass: args.initializerOwnerClass ?? null
75322
75504
  });
75323
75505
  if (!isMemberValue(candidate) || !isInitValueContent(candidate)) {
75324
75506
  throw new Error(
75325
75507
  `Construction replay for value "${args.valueId}" did not compile an initializer row.`
75326
75508
  );
75327
75509
  }
75510
+ if (args.evaluate === false) return /* @__PURE__ */ new Map();
75328
75511
  const materialized = materializeInitializerValue({
75329
75512
  document,
75330
75513
  // Constructor-only rows have no structural member owner. Use the same
@@ -76434,7 +76617,7 @@ function lowerRowBackedDefault(context, member, backed, baseData3, binding) {
76434
76617
  const assignmentSlices = objectInitializerSlices(binding.initializer);
76435
76618
  for (const assignment of expression.initializer ?? []) {
76436
76619
  const childMember = classMemberByName(context, classId, assignment.name);
76437
- if (inheritedConstructorProjections(context.classes, schemaClass2.id).some(
76620
+ if (inheritedConstructorProjections2(context.classes, schemaClass2.id).some(
76438
76621
  (projection) => projection.memberId === childMember.id
76439
76622
  )) {
76440
76623
  throw new Error(
@@ -76847,7 +77030,7 @@ function lowerSeedRow(context, member, sourceExpression, source, valueId, path,
76847
77030
  effectiveClass.id,
76848
77031
  assignment.name
76849
77032
  );
76850
- if (inheritedConstructorProjections(
77033
+ if (inheritedConstructorProjections2(
76851
77034
  context.classes,
76852
77035
  effectiveClass.id
76853
77036
  ).some((projection) => projection.memberId === childMember.id)) {
@@ -77145,15 +77328,17 @@ function lowerValueRow(context, member, sourceExpression, expectedValueId, sourc
77145
77328
  `Value ${expectedValueId} stores constructor arguments but its declared member ${resolvedMember.name} is not a Class.`
77146
77329
  );
77147
77330
  }
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
- });
77331
+ if (source.purpose === "stored") {
77332
+ context.initializerReconciliations.set(expectedValueId, {
77333
+ valueId: expectedValueId,
77334
+ code,
77335
+ storedConstructorArgs: storedConstructorArgs === null ? null : structuredClone(storedConstructorArgs),
77336
+ settleFields: expression.kind === "new" ? (expression.initializer ?? []).map(
77337
+ (assignment) => assignment.name
77338
+ ) : [],
77339
+ site: referenceSite(source, expression)
77340
+ });
77341
+ }
77157
77342
  const value2 = lowerClassValue(
77158
77343
  context,
77159
77344
  resolvedMember,
@@ -77348,7 +77533,7 @@ function lowerClassValue(context, member, expression, base, source, outerEnviron
77348
77533
  }
77349
77534
  for (const assignment of expression.initializer ?? []) {
77350
77535
  const childMember = classMemberByName(context, classId, assignment.name);
77351
- if (inheritedConstructorProjections(context.classes, schemaClass2.id).some(
77536
+ if (inheritedConstructorProjections2(context.classes, schemaClass2.id).some(
77352
77537
  (projection) => projection.memberId === childMember.id
77353
77538
  )) {
77354
77539
  throw new Error(
@@ -77530,7 +77715,7 @@ function classInheritanceChain(classes, classId) {
77530
77715
  }
77531
77716
  return chain;
77532
77717
  }
77533
- function inheritedConstructorProjections(classes, classId) {
77718
+ function inheritedConstructorProjections2(classes, classId) {
77534
77719
  const resolved = [];
77535
77720
  const claimed = /* @__PURE__ */ new Set();
77536
77721
  for (const schemaClass2 of classInheritanceChain(classes, classId)) {
@@ -77551,7 +77736,7 @@ function inheritedProjectionSchemaKey(classes, classId, memberId) {
77551
77736
  return null;
77552
77737
  }
77553
77738
  function resolveConstructorProjectionArguments(context, schemaClass2, expression, ownerValueId, environment, source) {
77554
- const projections = inheritedConstructorProjections(
77739
+ const projections = inheritedConstructorProjections2(
77555
77740
  context.classes,
77556
77741
  schemaClass2.id
77557
77742
  );
@@ -79856,7 +80041,7 @@ function manifestMemberTypeName(context, member) {
79856
80041
  return fixedSourceTypeNameForKind(member.kind) ?? member.kind;
79857
80042
  }
79858
80043
  function constructorProjectionSource(context, classId, body, visited, environment) {
79859
- const projections = inheritedConstructorProjections(
80044
+ const projections = inheritedConstructorProjections2(
79860
80045
  context.manifestClasses,
79861
80046
  classId
79862
80047
  );
@@ -84019,11 +84204,12 @@ function replayAnimationDeclarationInitializersV4(records2, document) {
84019
84204
  });
84020
84205
  if (initializers.length === 0) return document;
84021
84206
  const rootKinds = /* @__PURE__ */ new Map();
84207
+ const rootOwners = /* @__PURE__ */ new Map();
84022
84208
  const owners = resolveOwnerMembersForValues(
84023
84209
  document,
84024
84210
  new Set(initializers.map(({ row }) => row.id)),
84025
84211
  void 0,
84026
- void 0,
84212
+ rootOwners,
84027
84213
  rootKinds
84028
84214
  );
84029
84215
  const pulled = /* @__PURE__ */ new Map();
@@ -84048,12 +84234,20 @@ function replayAnimationDeclarationInitializersV4(records2, document) {
84048
84234
  if (!classBelongsToAnimationFamily(document.classes, declaredClassId)) {
84049
84235
  continue;
84050
84236
  }
84237
+ const rootOwner = rootOwners.get(row.id);
84238
+ const rootOwnerId = Reflect.get(rootOwner ?? {}, "id");
84239
+ const initializerOwnerClass = typeof rootOwnerId !== "string" ? null : findSchemaPlacement(rootOwnerId, document.classes)?.ownerClass ?? null;
84051
84240
  const replay = replayStoredConstructionV4({
84052
84241
  records: pulled,
84053
84242
  valueId: row.id,
84054
84243
  code,
84055
84244
  member: owner,
84056
- compileDocumentBodies: true
84245
+ compileDocumentBodies: true,
84246
+ initializerOwnerClass,
84247
+ // A parameterized declaration is a template. Its arguments exist only
84248
+ // at concrete construction sites, so validate the authored body here
84249
+ // without fabricating values for the class header parameters.
84250
+ evaluate: initializerOwnerClass?.requiredConstructorId === void 0 || initializerOwnerClass.requiredConstructorId === null
84057
84251
  });
84058
84252
  for (const [id2, value] of replay) {
84059
84253
  if (!isMemberValue(value)) {
@@ -84437,6 +84631,7 @@ var init_workspace_status = __esm({
84437
84631
  init_project_documents();
84438
84632
  init_animation_clips();
84439
84633
  init_classes();
84634
+ init_inheritance();
84440
84635
  init_members();
84441
84636
  init_value_row_owner_members();
84442
84637
  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.4",
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.4 -->
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.4 -->
77
77
  ```
78
78
 
79
79
  The quoted version above is checked too, so this instruction cannot go stale