@neocompose/cli 0.31.6 → 0.31.7

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,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.31.7] - 2026-08-15
4
+
5
+ ### Fixed
6
+
7
+ - Preserve forwarded type arguments in constructed generic constraints such
8
+ as `TItem extends InventoryItem<TItemData>` through push, pull, stored-body
9
+ replay, validation, and C# generation.
10
+
3
11
  ## [0.31.6] - 2026-08-15
4
12
 
5
13
  ### Added
package/dist/neo.mjs CHANGED
@@ -17796,7 +17796,7 @@ var init_project_schema_contract_generated = __esm({
17796
17796
  "../packages/neoscript-language/src/project-schema-contract.generated.ts"() {
17797
17797
  "use strict";
17798
17798
  PROJECT_SCHEMA_MANIFEST_FORMAT_VERSION = 3;
17799
- PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION = "3.12";
17799
+ PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION = "3.13";
17800
17800
  PROJECT_FILE_UPLOAD_BATCH_SIZE = 32;
17801
17801
  NEO_PROJECT_SOURCE_RECORD_CONTRACT = {
17802
17802
  "recordFields": {
@@ -30758,15 +30758,21 @@ function projectSchemaManifest(input, options = {}) {
30758
30758
  "ProjectSchemaManifest.interfaces"
30759
30759
  );
30760
30760
  const genericNames = /* @__PURE__ */ new Map();
30761
+ const genericDeclarations = /* @__PURE__ */ new Map();
30762
+ const genericOwnerClassIds = /* @__PURE__ */ new Map();
30761
30763
  for (const schemaClass2 of classes) {
30764
+ const classId = string2(schemaClass2.id, "schemaClass.id");
30762
30765
  for (const parameter4 of records(
30763
30766
  schemaClass2.genericParameters ?? [],
30764
30767
  "schemaClass.genericParameters"
30765
30768
  )) {
30769
+ const parameterId = string2(parameter4.id, "genericParameter.id");
30766
30770
  genericNames.set(
30767
- string2(parameter4.id, "genericParameter.id"),
30771
+ parameterId,
30768
30772
  string2(parameter4.name, "genericParameter.name")
30769
30773
  );
30774
+ genericDeclarations.set(parameterId, parameter4);
30775
+ genericOwnerClassIds.set(parameterId, classId);
30770
30776
  }
30771
30777
  }
30772
30778
  const rootMemberIds2 = options.rootMemberIds ?? inferRootMemberIds(members);
@@ -30777,6 +30783,8 @@ function projectSchemaManifest(input, options = {}) {
30777
30783
  interfaces: interfaceById,
30778
30784
  enums: indexById(enums, "ProjectSchemaManifest.enums"),
30779
30785
  genericNames,
30786
+ genericDeclarations,
30787
+ genericOwnerClassIds,
30780
30788
  effectiveWritabilityByMemberId: effectiveMemberWritability(
30781
30789
  members,
30782
30790
  classes,
@@ -31150,7 +31158,7 @@ function schemaClass(value, environment, field) {
31150
31158
  return {
31151
31159
  id: parameterId,
31152
31160
  name,
31153
- type: { kind: "typeParameter", id: parameterId, name },
31161
+ type: typeParameter(parameterId, environment, false),
31154
31162
  ...spanAndSelectionLocations(
31155
31163
  parameter4.source,
31156
31164
  parameter4.selectionSpan ?? parameter4.source,
@@ -32139,14 +32147,73 @@ function manifestPrimitive(kind) {
32139
32147
  return null;
32140
32148
  }
32141
32149
  }
32142
- function typeParameter(id2, environment, nullable) {
32150
+ function typeParameter(id2, environment, nullable, visiting = /* @__PURE__ */ new Set()) {
32151
+ const declaration = environment.genericDeclarations.get(id2);
32152
+ const constraint = declaration?.constraint;
32153
+ const next = new Set(visiting).add(id2);
32143
32154
  return {
32144
32155
  kind: "typeParameter",
32145
32156
  id: id2,
32146
32157
  name: environment.genericNames.get(id2) ?? id2,
32158
+ ...environment.genericOwnerClassIds.has(id2) ? { ownerClassId: environment.genericOwnerClassIds.get(id2) } : {},
32159
+ ...visiting.has(id2) || constraint === void 0 || constraint === null ? {} : {
32160
+ constraint: genericConstraintType(
32161
+ constraint,
32162
+ environment,
32163
+ next,
32164
+ `generic parameter ${id2}.constraint`
32165
+ )
32166
+ },
32147
32167
  nullable
32148
32168
  };
32149
32169
  }
32170
+ function genericConstraintType(value, environment, visiting, field) {
32171
+ const constraint = record2(value, field);
32172
+ if (constraint.kind === "enum") {
32173
+ return {
32174
+ kind: "named",
32175
+ typeId: string2(constraint.enumId, `${field}.enumId`),
32176
+ nullable: false
32177
+ };
32178
+ }
32179
+ if (constraint.kind !== "class") {
32180
+ throw new Error(`${field}.kind must be "class" or "enum".`);
32181
+ }
32182
+ const classId = string2(constraint.classId, `${field}.classId`);
32183
+ const target = environment.classes.get(classId);
32184
+ const parameters = target ? records(target.genericParameters ?? [], `${field}.genericParameters`) : [];
32185
+ const bindings = optionalRecord(constraint.classArguments) ?? {};
32186
+ const typeArguments = parameters.flatMap((parameter4) => {
32187
+ const parameterId = string2(parameter4.id, `${field}.genericParameter.id`);
32188
+ const binding = optionalRecord(bindings[parameterId]);
32189
+ if (binding?.kind === "generic" && typeof binding.genericParamId === "string") {
32190
+ return [
32191
+ typeParameter(binding.genericParamId, environment, false, visiting)
32192
+ ];
32193
+ }
32194
+ if (binding?.kind === "member" && typeof binding.memberId === "string") {
32195
+ const member = environment.members.get(binding.memberId);
32196
+ return member ? [
32197
+ {
32198
+ ...memberType(
32199
+ member,
32200
+ environment,
32201
+ /* @__PURE__ */ new Set(),
32202
+ `${field}.classArguments.${parameterId}`
32203
+ ),
32204
+ nullable: false
32205
+ }
32206
+ ] : [];
32207
+ }
32208
+ return [];
32209
+ });
32210
+ return {
32211
+ kind: "named",
32212
+ typeId: classId,
32213
+ nullable: false,
32214
+ ...typeArguments.length === parameters.length && typeArguments.length > 0 ? { typeArguments } : {}
32215
+ };
32216
+ }
32150
32217
  function primitive(name, nullable) {
32151
32218
  return { kind: "primitive", name, nullable };
32152
32219
  }
@@ -34673,6 +34740,16 @@ function inferMemberOwners(classes, members) {
34673
34740
  schemaClass2.recordId,
34674
34741
  set
34675
34742
  );
34743
+ if (Array.isArray(schemaClass2.data.genericParams)) {
34744
+ for (const parameterValue of schemaClass2.data.genericParams) {
34745
+ if (!isRecord2(parameterValue)) continue;
34746
+ const parameterId = parameterValue.id;
34747
+ const constraint = parameterValue.constraint;
34748
+ if (typeof parameterId !== "string" || !isRecord2(constraint)) continue;
34749
+ if (constraint.kind !== "class") continue;
34750
+ collectGenericOwners(constraint.classArguments, parameterId, set);
34751
+ }
34752
+ }
34676
34753
  }
34677
34754
  for (const [memberId, member] of members) {
34678
34755
  if (typeof member.entryMemberId === "string") {
@@ -38073,8 +38150,19 @@ function assertGenericParameter(value, path) {
38073
38150
  if (parameter4.constraint === null) return;
38074
38151
  const constraint = requireRecord(parameter4.constraint, `${path}.constraint`);
38075
38152
  if (constraint.kind === "class") {
38076
- knownKeys(constraint, `${path}.constraint`, ["kind", "classId"]);
38153
+ knownKeysWithOptional(
38154
+ constraint,
38155
+ `${path}.constraint`,
38156
+ ["kind", "classId"],
38157
+ ["classArguments"]
38158
+ );
38077
38159
  nonEmptyString(constraint.classId, `${path}.constraint.classId`);
38160
+ if (constraint.classArguments !== void 0 && constraint.classArguments !== null) {
38161
+ assertGenericBindingRecord(
38162
+ constraint.classArguments,
38163
+ `${path}.constraint.classArguments`
38164
+ );
38165
+ }
38078
38166
  return;
38079
38167
  }
38080
38168
  if (constraint.kind === "enum") {
@@ -41812,7 +41900,9 @@ function isGenericParamConstraint(value) {
41812
41900
  if (v.kind === "class") {
41813
41901
  if (typeof v.classId !== "string") return false;
41814
41902
  if (v.classId.length === 0) return false;
41815
- return v.enumId === void 0;
41903
+ if (v.enumId !== void 0) return false;
41904
+ const argumentsValue = v.classArguments;
41905
+ return argumentsValue === void 0 || argumentsValue === null || isGenericBindingsRecord(argumentsValue);
41816
41906
  }
41817
41907
  if (v.kind === "enum") {
41818
41908
  if (typeof v.enumId !== "string") return false;
@@ -49582,11 +49672,7 @@ function emitClass(context, schemaClass2, memberIds) {
49582
49672
  const modifier = schemaClass2.isSealed ? "sealed " : schemaClass2.declarationModifier === "abstract" ? "abstract " : "";
49583
49673
  const generics = schemaClass2.genericParameters.length ? `<
49584
49674
  ${schemaClass2.genericParameters.map((parameter4) => {
49585
- const constraint = parameter4.constraint ? ` extends ${parameter4.constraint.kind === "class" ? required(
49586
- context.classes,
49587
- parameter4.constraint.classId,
49588
- "class"
49589
- ).name : required(context.enums, parameter4.constraint.enumId, "enum").name}` : "";
49675
+ const constraint = parameter4.constraint ? ` extends ${renderGenericConstraint(context, parameter4.constraint)}` : "";
49590
49676
  return ` ${id(parameter4.id)} ${parameter4.name}${constraint}`;
49591
49677
  }).join(",\n")}
49592
49678
  >` : "";
@@ -49660,6 +49746,31 @@ ${members.join("\n\n")}
49660
49746
  }
49661
49747
  `;
49662
49748
  }
49749
+ function renderGenericConstraint(context, constraint) {
49750
+ if (constraint.kind === "enum") {
49751
+ return required(context.enums, constraint.enumId, "enum").name;
49752
+ }
49753
+ const target = required(context.classes, constraint.classId, "class");
49754
+ if (target.genericParameters.length === 0) return target.name;
49755
+ const bindings = constraint.classArguments;
49756
+ if (bindings === void 0 || bindings === null) return target.name;
49757
+ const argumentsValue = target.genericParameters.map((parameter4) => {
49758
+ const binding = bindings[parameter4.id];
49759
+ if (binding === void 0) {
49760
+ throw new Error(
49761
+ `Generic constraint ${target.name} is missing its argument for ${parameter4.name}.`
49762
+ );
49763
+ }
49764
+ if (binding.kind === "generic") {
49765
+ return genericName(context, binding.genericParamId);
49766
+ }
49767
+ return renderMemberType(
49768
+ context,
49769
+ required(context.members, binding.memberId, "generic constraint binding")
49770
+ ).replace(/\?$/u, "");
49771
+ });
49772
+ return `${target.name}<${argumentsValue.join(", ")}>`;
49773
+ }
49663
49774
  function baseConstruction(requiredConstructor) {
49664
49775
  if (requiredConstructor === void 0) return "";
49665
49776
  const args = requiredConstructor.baseArguments ?? [];
@@ -56139,7 +56250,15 @@ function lowerClass(context, declaration) {
56139
56250
  return {
56140
56251
  id: parameterId,
56141
56252
  name: parameter4.name,
56142
- constraint: parameter4.constraint ? genericConstraint(context, parameter4.constraint) : null,
56253
+ constraint: parameter4.constraint ? genericConstraint(
56254
+ context,
56255
+ declaration,
56256
+ parameterId,
56257
+ parameter4.constraint,
56258
+ base?.genericParameters.find(
56259
+ (candidate) => candidate.id === parameterId
56260
+ )?.constraint
56261
+ ) : null,
56143
56262
  source: span(parameter4.identity),
56144
56263
  selectionSpan: span(parameter4.identity)
56145
56264
  };
@@ -58090,9 +58209,22 @@ function lowerGenericArgument(context, ownerClass, type, memberId, genericParamI
58090
58209
  )
58091
58210
  );
58092
58211
  }
58093
- function genericConstraint(context, type) {
58212
+ function genericConstraint(context, ownerClass, parameterId, type, baseConstraint) {
58094
58213
  const classId = context.classIdsByName.get(type.name);
58095
- if (classId) return { kind: "class", classId };
58214
+ if (classId) {
58215
+ const classArguments2 = type.arguments.length === 0 ? void 0 : lowerClassArguments(
58216
+ context,
58217
+ ownerClass,
58218
+ parameterId,
58219
+ type,
58220
+ baseConstraint?.kind === "class" ? baseConstraint.classArguments ?? void 0 : void 0
58221
+ );
58222
+ return {
58223
+ kind: "class",
58224
+ classId,
58225
+ ...classArguments2 === void 0 ? {} : { classArguments: classArguments2 }
58226
+ };
58227
+ }
58096
58228
  return {
58097
58229
  kind: "enum",
58098
58230
  enumId: requiredName2(context.enumIdsByName, type.name, "enum")
@@ -58998,18 +59130,12 @@ function classToLanguageType(schemaClass2, context) {
58998
59130
  typeParameters: schemaClass2.genericParams.map((parameter4) => ({
58999
59131
  id: parameter4.id,
59000
59132
  name: parameter4.name,
59001
- type: {
59002
- kind: "typeParameter",
59003
- id: parameter4.id,
59004
- name: parameter4.name,
59005
- ownerClassId: schemaClass2.id,
59006
- ...parameter4.constraint === void 0 || parameter4.constraint === null ? {} : {
59007
- constraint: namedType(
59008
- parameter4.constraint.kind === "class" ? parameter4.constraint.classId : parameter4.constraint.enumId,
59009
- true
59010
- )
59011
- }
59012
- },
59133
+ type: genericParameterLanguageType(
59134
+ parameter4.id,
59135
+ true,
59136
+ context,
59137
+ genericEnvironment
59138
+ ),
59013
59139
  location: virtualIdentifierLocation(
59014
59140
  context,
59015
59141
  "Classes",
@@ -59659,31 +59785,12 @@ function memberRuntimeType(record3, context, seen = /* @__PURE__ */ new Set(), g
59659
59785
  );
59660
59786
  }
59661
59787
  }
59662
- for (const owner of context.vm.classes) {
59663
- const parameter4 = owner.genericParams?.find(
59664
- (candidate) => candidate.id === genericParamId
59665
- );
59666
- if (parameter4) {
59667
- if (parameter4.constraint?.kind === "class") {
59668
- return namedType(parameter4.constraint.classId, required2);
59669
- }
59670
- if (parameter4.constraint?.kind === "enum") {
59671
- return namedType(parameter4.constraint.enumId, required2);
59672
- }
59673
- return {
59674
- kind: "typeParameter",
59675
- id: genericParamId,
59676
- name: parameter4.name,
59677
- nullable: !required2
59678
- };
59679
- }
59680
- }
59681
- return {
59682
- kind: "typeParameter",
59683
- id: genericParamId,
59684
- name: genericParamId,
59685
- nullable: !required2
59686
- };
59788
+ return genericParameterLanguageType(
59789
+ genericParamId,
59790
+ required2,
59791
+ context,
59792
+ genericEnvironment
59793
+ );
59687
59794
  }
59688
59795
  case 27 /* Variant */: {
59689
59796
  if (!isMemberVariantBase(member)) return UNKNOWN_TYPE2;
@@ -59746,13 +59853,13 @@ function classArguments(member, context, seen, genericEnvironment) {
59746
59853
  )
59747
59854
  ] : [];
59748
59855
  }
59749
- const declaration = context.vm.classes.flatMap((schemaClass2) => schemaClass2.genericParams ?? []).find((candidate) => candidate.id === binding.genericParamId);
59750
59856
  return [
59751
- {
59752
- kind: "typeParameter",
59753
- id: binding.genericParamId,
59754
- name: declaration?.name ?? binding.genericParamId
59755
- }
59857
+ genericParameterLanguageType(
59858
+ binding.genericParamId,
59859
+ true,
59860
+ context,
59861
+ genericEnvironment
59862
+ )
59756
59863
  ];
59757
59864
  }
59758
59865
  const argument2 = analyzerMemberById(context.vm, binding.memberId);
@@ -59900,33 +60007,89 @@ function toLanguageType(type, context, genericEnvironment) {
59900
60007
  );
59901
60008
  }
59902
60009
  }
59903
- const effectiveParamId = environmentEntry?.kind === "unbound" ? environmentEntry.paramId : type.genericParamId;
59904
- const owner = context.vm.classes.find(
59905
- (item) => item.id === type.ownerClassId || item.genericParams?.some(
59906
- (parameter4) => parameter4.id === effectiveParamId
59907
- )
60010
+ return genericParameterLanguageType(
60011
+ environmentEntry?.kind === "unbound" ? environmentEntry.paramId : type.genericParamId,
60012
+ required2,
60013
+ context,
60014
+ genericEnvironment
59908
60015
  );
59909
- const name = owner?.genericParams?.find(
59910
- (parameter4) => parameter4.id === effectiveParamId
59911
- )?.name ?? effectiveParamId;
59912
- const declaration = owner?.genericParams?.find(
59913
- (parameter4) => parameter4.id === effectiveParamId
60016
+ }
60017
+ }
60018
+ }
60019
+ function genericParameterLanguageType(genericParamId, required2, context, genericEnvironment, visiting = /* @__PURE__ */ new Set()) {
60020
+ const environmentEntry = genericEnvironment?.get(genericParamId);
60021
+ if (environmentEntry?.kind === "member") {
60022
+ const binding = analyzerMemberById(context.vm, environmentEntry.memberId);
60023
+ if (binding) {
60024
+ return requiredType(
60025
+ memberRuntimeType(binding, context, /* @__PURE__ */ new Set(), genericEnvironment)
59914
60026
  );
59915
- return {
59916
- kind: "typeParameter",
59917
- id: effectiveParamId,
59918
- name,
59919
- ...owner === void 0 ? {} : { ownerClassId: owner.id },
59920
- ...declaration?.constraint === void 0 || declaration.constraint === null ? {} : {
59921
- constraint: namedType(
59922
- declaration.constraint.kind === "class" ? declaration.constraint.classId : declaration.constraint.enumId,
59923
- true
59924
- )
59925
- },
59926
- nullable: !required2
59927
- };
59928
60027
  }
59929
60028
  }
60029
+ const effectiveParamId = environmentEntry?.kind === "unbound" ? environmentEntry.paramId : genericParamId;
60030
+ const owner = context.vm.classes.find(
60031
+ (schemaClass2) => schemaClass2.genericParams?.some(
60032
+ (parameter4) => parameter4.id === effectiveParamId
60033
+ )
60034
+ );
60035
+ const declaration = owner?.genericParams?.find(
60036
+ (parameter4) => parameter4.id === effectiveParamId
60037
+ );
60038
+ const next = new Set(visiting).add(effectiveParamId);
60039
+ return {
60040
+ kind: "typeParameter",
60041
+ id: effectiveParamId,
60042
+ name: declaration?.name ?? effectiveParamId,
60043
+ ...owner === void 0 ? {} : { ownerClassId: owner.id },
60044
+ ...visiting.has(effectiveParamId) || declaration?.constraint == null ? {} : {
60045
+ constraint: genericConstraintLanguageType(
60046
+ declaration.constraint,
60047
+ context,
60048
+ genericEnvironment,
60049
+ next
60050
+ )
60051
+ },
60052
+ nullable: !required2
60053
+ };
60054
+ }
60055
+ function genericConstraintLanguageType(constraint, context, genericEnvironment, visiting = /* @__PURE__ */ new Set()) {
60056
+ if (constraint.kind === "enum") {
60057
+ return namedType(constraint.enumId, true);
60058
+ }
60059
+ const target = context.vm.classes.find(
60060
+ (schemaClass2) => schemaClass2.id === constraint.classId
60061
+ );
60062
+ const bindings = constraint.classArguments;
60063
+ if (!target?.genericParams?.length || bindings == null) {
60064
+ return namedType(constraint.classId, true);
60065
+ }
60066
+ const typeArguments = target.genericParams.flatMap((parameter4) => {
60067
+ const binding = bindings[parameter4.id];
60068
+ if (binding === void 0) return [];
60069
+ if (binding.kind === "generic") {
60070
+ return [
60071
+ genericParameterLanguageType(
60072
+ binding.genericParamId,
60073
+ true,
60074
+ context,
60075
+ genericEnvironment,
60076
+ visiting
60077
+ )
60078
+ ];
60079
+ }
60080
+ const member = analyzerMemberById(context.vm, binding.memberId);
60081
+ return member ? [
60082
+ requiredType(
60083
+ memberRuntimeType(member, context, /* @__PURE__ */ new Set(), genericEnvironment)
60084
+ )
60085
+ ] : [];
60086
+ });
60087
+ return {
60088
+ kind: "named",
60089
+ typeId: constraint.classId,
60090
+ nullable: false,
60091
+ ...typeArguments.length === target.genericParams.length ? { typeArguments } : {}
60092
+ };
59930
60093
  }
59931
60094
  function functionReturnType(type, context, genericEnvironment) {
59932
60095
  return type.type === NS_TYPE_VOID ? primitive2("void", true) : toLanguageType(type, context, genericEnvironment);
@@ -60094,12 +60257,68 @@ function virtualNeoSchemaClassHeader(schemaClass2, context) {
60094
60257
  )?.name ?? constraint.classId : context.vm.enums.find(
60095
60258
  (candidate) => candidate.id === constraint.enumId
60096
60259
  )?.name ?? constraint.enumId;
60260
+ const targetClass = constraint.kind === "class" ? context.vm.classes.find(
60261
+ (candidate) => candidate.id === constraint.classId
60262
+ ) : void 0;
60263
+ const bindings = constraint.kind === "class" ? constraint.classArguments : void 0;
60264
+ const argumentsValue = targetClass?.genericParams?.flatMap(
60265
+ (targetParameter) => {
60266
+ const binding = bindings?.[targetParameter.id];
60267
+ if (binding?.kind === "generic") {
60268
+ const declaration = context.vm.classes.flatMap((candidate) => candidate.genericParams ?? []).find((candidate) => candidate.id === binding.genericParamId);
60269
+ return [
60270
+ virtualCSharpIdentifier(
60271
+ declaration?.name ?? binding.genericParamId
60272
+ )
60273
+ ];
60274
+ }
60275
+ if (binding?.kind === "member") {
60276
+ const member = analyzerMemberById(context.vm, binding.memberId);
60277
+ return [
60278
+ member ? virtualConstraintMemberType(member, context) : "object"
60279
+ ];
60280
+ }
60281
+ return [];
60282
+ }
60283
+ );
60284
+ const argumentSuffix = targetClass?.genericParams?.length && argumentsValue?.length === targetClass.genericParams.length ? `<${argumentsValue.join(", ")}>` : "";
60097
60285
  return [
60098
- ` where ${virtualCSharpIdentifier(parameter4.name)} : ${virtualCSharpIdentifier(target)}`
60286
+ ` where ${virtualCSharpIdentifier(parameter4.name)} : ${virtualCSharpIdentifier(target)}${argumentSuffix}`
60099
60287
  ];
60100
60288
  });
60101
60289
  return `public ${schemaClass2.isAbstract ? "abstract " : ""}partial class ${virtualCSharpIdentifier(schemaClass2.name)}${genericParameters}${inheritance}${constraints.join("")} // Neo class ${schemaClass2.id}`;
60102
60290
  }
60291
+ function virtualConstraintMemberType(member, context) {
60292
+ const resolved = resolveMember2(member, context.vm.members);
60293
+ switch (resolved.kind) {
60294
+ case 1 /* Bool */:
60295
+ return "bool";
60296
+ case 2 /* Int */:
60297
+ return "int";
60298
+ case 3 /* String */:
60299
+ return "string";
60300
+ case 4 /* Float */:
60301
+ return "double";
60302
+ case 20 /* Decimal */:
60303
+ return "decimal";
60304
+ case 7 /* Class */: {
60305
+ const classId = getOptionalString(resolved, "classId");
60306
+ const schemaClass2 = context.vm.classes.find(
60307
+ (candidate) => candidate.id === classId
60308
+ );
60309
+ return virtualCSharpIdentifier(schemaClass2?.name ?? classId ?? "object");
60310
+ }
60311
+ case 8 /* Enum */: {
60312
+ const enumId = getOptionalString(resolved, "enumId");
60313
+ const neoEnum = context.vm.enums.find(
60314
+ (candidate) => candidate.id === enumId
60315
+ );
60316
+ return virtualCSharpIdentifier(neoEnum?.name ?? enumId ?? "object");
60317
+ }
60318
+ default:
60319
+ return "object";
60320
+ }
60321
+ }
60103
60322
  function virtualNeoSchemaClassMemberLine(schemaKey, displayName, memberId) {
60104
60323
  return ` public object? ${virtualCSharpIdentifier(schemaKey)} { get; init; } // ${displayName}; Neo member ${memberId}`;
60105
60324
  }
@@ -60135,7 +60354,7 @@ var init_neoscript_language_context_adapter = __esm({
60135
60354
  init_project_root_members();
60136
60355
  init_project_file_registry();
60137
60356
  init_analyzer_types();
60138
- NEOSCRIPT_COMPILER_ADAPTER_REVISION = 1;
60357
+ NEOSCRIPT_COMPILER_ADAPTER_REVISION = 2;
60139
60358
  UNKNOWN_TYPE2 = {
60140
60359
  kind: "primitive",
60141
60360
  name: "unknown"
@@ -82237,10 +82456,13 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
82237
82456
  `Class "${schemaClass2.name}" (${schemaClass2.id}) cannot extend sealed class "${baseClass.name}" (${baseClass.id}).`
82238
82457
  );
82239
82458
  }
82240
- const genericParamConstraintsById = new Map(
82459
+ const genericParamDeclarationsById = new Map(
82241
82460
  classes.flatMap(
82242
82461
  (schemaClass2) => (schemaClass2.genericParams ?? []).map(
82243
- (param) => [param.id, param.constraint]
82462
+ (param) => [
82463
+ param.id,
82464
+ { constraint: param.constraint, ownerClassId: schemaClass2.id }
82465
+ ]
82244
82466
  )
82245
82467
  )
82246
82468
  );
@@ -83155,13 +83377,40 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
83155
83377
  if (!isRecord7(typeInfo) || typeInfo.type !== 21 || typeof typeInfo.genericParamId !== "string") {
83156
83378
  return null;
83157
83379
  }
83158
- const constraint = genericParamConstraintsById.get(typeInfo.genericParamId);
83380
+ const constraint = genericParamDeclarationsById.get(
83381
+ typeInfo.genericParamId
83382
+ )?.constraint;
83159
83383
  if (!constraint) return null;
83160
- return constraint.kind === "class" ? {
83161
- type: 7,
83162
- required: typeInfo.required === true,
83163
- classId: constraint.classId
83164
- } : {
83384
+ if (constraint.kind === "class") {
83385
+ const typeArguments = Object.fromEntries(
83386
+ Object.entries(constraint.classArguments ?? {}).flatMap(
83387
+ ([parameterId, binding]) => {
83388
+ if (binding.kind !== "generic") return [];
83389
+ const ownerClassId = genericParamDeclarationsById.get(
83390
+ binding.genericParamId
83391
+ )?.ownerClassId;
83392
+ return ownerClassId === void 0 ? [] : [
83393
+ [
83394
+ parameterId,
83395
+ {
83396
+ type: 21,
83397
+ required: true,
83398
+ ownerClassId,
83399
+ genericParamId: binding.genericParamId
83400
+ }
83401
+ ]
83402
+ ];
83403
+ }
83404
+ )
83405
+ );
83406
+ return {
83407
+ type: 7,
83408
+ required: typeInfo.required === true,
83409
+ classId: constraint.classId,
83410
+ ...Object.keys(typeArguments).length > 0 ? { typeArguments } : {}
83411
+ };
83412
+ }
83413
+ return {
83165
83414
  type: 8,
83166
83415
  required: typeInfo.required === true,
83167
83416
  enumId: constraint.enumId
@@ -111011,8 +111260,8 @@ var init_registry2 = __esm({
111011
111260
  "use strict";
111012
111261
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
111013
111262
  formatVersion: 3,
111014
- contractVersion: "3.12",
111015
- cliVersion: "0.31.6",
111263
+ contractVersion: "3.13",
111264
+ cliVersion: "0.31.7",
111016
111265
  projectFileUploadBatchSize: 32,
111017
111266
  documentRecords: {
111018
111267
  member: {
@@ -117607,7 +117856,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
117607
117856
  async function main() {
117608
117857
  const args = parseArgs(process.argv.slice(2));
117609
117858
  if (args.command === "--version") {
117610
- console.log("0.31.6");
117859
+ console.log("0.31.7");
117611
117860
  return;
117612
117861
  }
117613
117862
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.31.6",
3
+ "version": "0.31.7",
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.31.6 -->
12
+ <!-- reviewed-through-cli: 0.31.7 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -83,7 +83,7 @@ wrappers.
83
83
  The marker near the top of `SKILL.md` must exactly match the package version:
84
84
 
85
85
  ```html
86
- <!-- reviewed-through-cli: 0.31.6 -->
86
+ <!-- reviewed-through-cli: 0.31.7 -->
87
87
  ```
88
88
 
89
89
  The quoted version above is checked too, so this instruction cannot go stale
@@ -287,3 +287,16 @@ class Child(string name) : Base {
287
287
  Bind generic base arguments explicitly when needed. Reject a subclass that
288
288
  omits required base arguments or leaves any inherited required member
289
289
  unsettled.
290
+
291
+ Generic constraints may construct another generic from a parameter in the
292
+ same declaration. This preserves the relationship between the parameters in
293
+ source checks, stored initializer replay, and generated C#:
294
+
295
+ ```neo
296
+ class PlacedItem<
297
+ TData extends InventoryStackData,
298
+ TItem extends InventoryItem<TData>
299
+ >(TItem item) {
300
+ public TData Data = item.DefaultData.Clone();
301
+ }
302
+ ```