@neocompose/cli 0.31.6 → 0.31.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/neo.mjs +375 -111
- package/package.json +1 -1
- package/skills/neocompose-cli/SKILL.md +1 -1
- package/skills/neocompose-cli/references/cli-development.md +1 -1
- package/skills/neocompose-cli/references/declarations-and-construction.md +13 -0
- package/skills/neocompose-cli/references/neoscript.md +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.31.8] - 2026-08-17
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Propagate `?.` through following required member and index accesses in the
|
|
8
|
+
same expression chain, so a nullable parent safely short-circuits a deep
|
|
9
|
+
read while independently nullable descendants still require explicit null
|
|
10
|
+
handling.
|
|
11
|
+
|
|
12
|
+
## [0.31.7] - 2026-08-15
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Preserve forwarded type arguments in constructed generic constraints such
|
|
17
|
+
as `TItem extends InventoryItem<TItemData>` through push, pull, stored-body
|
|
18
|
+
replay, validation, and C# generation.
|
|
19
|
+
|
|
3
20
|
## [0.31.6] - 2026-08-15
|
|
4
21
|
|
|
5
22
|
### Added
|
package/dist/neo.mjs
CHANGED
|
@@ -11838,13 +11838,15 @@ var init_strict_resolver = __esm({
|
|
|
11838
11838
|
};
|
|
11839
11839
|
}
|
|
11840
11840
|
}
|
|
11841
|
-
const
|
|
11842
|
-
if (optional && !isNullable(
|
|
11841
|
+
const resolvedReceiver = this.resolveExpression(receiverAst, scope);
|
|
11842
|
+
if (optional && !isNullable(resolvedReceiver.type)) {
|
|
11843
11843
|
throw new CompileError(
|
|
11844
|
-
`\`?.\` requires an optional receiver; got ${this.describe(
|
|
11844
|
+
`\`?.\` requires an optional receiver; got ${this.describe(resolvedReceiver.type)}`,
|
|
11845
11845
|
pos
|
|
11846
11846
|
);
|
|
11847
11847
|
}
|
|
11848
|
+
const receiver = resolvedReceiver.optionalChainType ? { ...resolvedReceiver, type: resolvedReceiver.optionalChainType } : resolvedReceiver;
|
|
11849
|
+
const nullPropagating = optional || resolvedReceiver.optionalChainType !== void 0;
|
|
11848
11850
|
if (!optional && isNullable(receiver.type)) {
|
|
11849
11851
|
throw new CompileError(
|
|
11850
11852
|
`Member '${name}' is read on ${this.describe(receiver.type)}, which may be null. Handle null before reading through it \u2014 use \`!\` if it is always set, or \`?.\`, \`??\`, or a null check that narrows it.`,
|
|
@@ -11852,7 +11854,7 @@ var init_strict_resolver = __esm({
|
|
|
11852
11854
|
);
|
|
11853
11855
|
}
|
|
11854
11856
|
if (receiver.staticType?.kind === "enum") {
|
|
11855
|
-
if (
|
|
11857
|
+
if (nullPropagating) {
|
|
11856
11858
|
throw new CompileError(
|
|
11857
11859
|
`\`?.\` is not valid on enum type '${receiver.staticType.name}'; enum option access is always defined`,
|
|
11858
11860
|
pos
|
|
@@ -11924,9 +11926,10 @@ var init_strict_resolver = __esm({
|
|
|
11924
11926
|
pointer: receiver.pointer,
|
|
11925
11927
|
key: numberPointer(0)
|
|
11926
11928
|
},
|
|
11927
|
-
...
|
|
11929
|
+
...nullPropagating ? { optional: true } : {}
|
|
11928
11930
|
},
|
|
11929
|
-
type:
|
|
11931
|
+
type: nullPropagating ? { ...primitiveMember.type, nullable: true } : primitiveMember.type,
|
|
11932
|
+
...nullPropagating ? { optionalChainType: primitiveMember.type } : {},
|
|
11930
11933
|
...receiver.writability ? { writability: receiver.writability } : {}
|
|
11931
11934
|
};
|
|
11932
11935
|
}
|
|
@@ -11934,7 +11937,7 @@ var init_strict_resolver = __esm({
|
|
|
11934
11937
|
receiver,
|
|
11935
11938
|
primitiveMember.key ?? name,
|
|
11936
11939
|
primitiveMember.type,
|
|
11937
|
-
|
|
11940
|
+
nullPropagating
|
|
11938
11941
|
);
|
|
11939
11942
|
if (!primitiveMember.derived) return resolved;
|
|
11940
11943
|
return {
|
|
@@ -11968,7 +11971,7 @@ var init_strict_resolver = __esm({
|
|
|
11968
11971
|
receiver,
|
|
11969
11972
|
name,
|
|
11970
11973
|
{ kind: "primitive", name: "string" },
|
|
11971
|
-
|
|
11974
|
+
nullPropagating
|
|
11972
11975
|
);
|
|
11973
11976
|
}
|
|
11974
11977
|
const member = type.members.find((candidate) => candidate.name === name);
|
|
@@ -12002,9 +12005,10 @@ var init_strict_resolver = __esm({
|
|
|
12002
12005
|
type: "callGetter" /* CallGetter */,
|
|
12003
12006
|
memberId: member.id,
|
|
12004
12007
|
receiver: { kind: "instance", pointer: receiver.pointer },
|
|
12005
|
-
...
|
|
12008
|
+
...nullPropagating ? { optional: true } : {}
|
|
12006
12009
|
},
|
|
12007
|
-
type:
|
|
12010
|
+
type: nullPropagating ? { ...memberType2, nullable: true } : memberType2,
|
|
12011
|
+
...nullPropagating ? { optionalChainType: memberType2 } : {},
|
|
12008
12012
|
symbol: member,
|
|
12009
12013
|
...member.writable ? {
|
|
12010
12014
|
writability: member.writability ? toWritability(member.writability) : "setter" /* Setter */
|
|
@@ -12028,7 +12032,7 @@ var init_strict_resolver = __esm({
|
|
|
12028
12032
|
receiver,
|
|
12029
12033
|
member.schemaKey ?? member.name,
|
|
12030
12034
|
memberType2,
|
|
12031
|
-
|
|
12035
|
+
nullPropagating,
|
|
12032
12036
|
member.id
|
|
12033
12037
|
),
|
|
12034
12038
|
symbol: member,
|
|
@@ -12136,14 +12140,23 @@ var init_strict_resolver = __esm({
|
|
|
12136
12140
|
...optional ? { optional: true } : {}
|
|
12137
12141
|
},
|
|
12138
12142
|
type: optional ? { ...type, nullable: true } : type,
|
|
12143
|
+
...optional ? { optionalChainType: type } : {},
|
|
12139
12144
|
...receiver.writability ? { writability: receiver.writability } : {}
|
|
12140
12145
|
};
|
|
12141
12146
|
}
|
|
12142
12147
|
resolveIndex(receiverAst, indexAst, scope, pos, optional) {
|
|
12143
|
-
const
|
|
12144
|
-
if (optional && !isNullable(
|
|
12148
|
+
const resolvedReceiver = this.resolveExpression(receiverAst, scope);
|
|
12149
|
+
if (optional && !isNullable(resolvedReceiver.type)) {
|
|
12145
12150
|
throw new CompileError(
|
|
12146
|
-
`\`?.[]\` requires an optional receiver; got ${this.describe(
|
|
12151
|
+
`\`?.[]\` requires an optional receiver; got ${this.describe(resolvedReceiver.type)}`,
|
|
12152
|
+
pos
|
|
12153
|
+
);
|
|
12154
|
+
}
|
|
12155
|
+
const receiver = resolvedReceiver.optionalChainType ? { ...resolvedReceiver, type: resolvedReceiver.optionalChainType } : resolvedReceiver;
|
|
12156
|
+
const nullPropagating = optional || resolvedReceiver.optionalChainType !== void 0;
|
|
12157
|
+
if (!optional && isNullable(receiver.type)) {
|
|
12158
|
+
throw new CompileError(
|
|
12159
|
+
`Index access is read on ${this.describe(receiver.type)}, which may be null. Handle null before indexing it \u2014 use \`!\` if it is always set, or \`?.[]\`, \`??\`, or a null check that narrows it.`,
|
|
12147
12160
|
pos
|
|
12148
12161
|
);
|
|
12149
12162
|
}
|
|
@@ -12185,9 +12198,10 @@ var init_strict_resolver = __esm({
|
|
|
12185
12198
|
pointer: {
|
|
12186
12199
|
type: "keyOf" /* KeyOf */,
|
|
12187
12200
|
keyOf: { pointer: receiver.pointer, key: requested.pointer },
|
|
12188
|
-
...
|
|
12201
|
+
...nullPropagating ? { optional: true } : {}
|
|
12189
12202
|
},
|
|
12190
|
-
type:
|
|
12203
|
+
type: nullPropagating ? { ...receiver.type.elementType, nullable: true } : receiver.type.elementType,
|
|
12204
|
+
...nullPropagating ? { optionalChainType: receiver.type.elementType } : {},
|
|
12191
12205
|
...receiver.writability ? { writability: receiver.writability } : {}
|
|
12192
12206
|
};
|
|
12193
12207
|
}
|
|
@@ -12218,9 +12232,10 @@ var init_strict_resolver = __esm({
|
|
|
12218
12232
|
pointer: {
|
|
12219
12233
|
type: "keyOf" /* KeyOf */,
|
|
12220
12234
|
keyOf: { pointer: receiver.pointer, key: index.pointer },
|
|
12221
|
-
...
|
|
12235
|
+
...nullPropagating ? { optional: true } : {}
|
|
12222
12236
|
},
|
|
12223
|
-
type:
|
|
12237
|
+
type: nullPropagating ? { ...valueType, nullable: true } : valueType,
|
|
12238
|
+
...nullPropagating ? { optionalChainType: valueType } : {},
|
|
12224
12239
|
...receiver.writability ? { writability: receiver.writability } : {}
|
|
12225
12240
|
};
|
|
12226
12241
|
}
|
|
@@ -17796,7 +17811,7 @@ var init_project_schema_contract_generated = __esm({
|
|
|
17796
17811
|
"../packages/neoscript-language/src/project-schema-contract.generated.ts"() {
|
|
17797
17812
|
"use strict";
|
|
17798
17813
|
PROJECT_SCHEMA_MANIFEST_FORMAT_VERSION = 3;
|
|
17799
|
-
PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION = "3.
|
|
17814
|
+
PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION = "3.13";
|
|
17800
17815
|
PROJECT_FILE_UPLOAD_BATCH_SIZE = 32;
|
|
17801
17816
|
NEO_PROJECT_SOURCE_RECORD_CONTRACT = {
|
|
17802
17817
|
"recordFields": {
|
|
@@ -30758,15 +30773,21 @@ function projectSchemaManifest(input, options = {}) {
|
|
|
30758
30773
|
"ProjectSchemaManifest.interfaces"
|
|
30759
30774
|
);
|
|
30760
30775
|
const genericNames = /* @__PURE__ */ new Map();
|
|
30776
|
+
const genericDeclarations = /* @__PURE__ */ new Map();
|
|
30777
|
+
const genericOwnerClassIds = /* @__PURE__ */ new Map();
|
|
30761
30778
|
for (const schemaClass2 of classes) {
|
|
30779
|
+
const classId = string2(schemaClass2.id, "schemaClass.id");
|
|
30762
30780
|
for (const parameter4 of records(
|
|
30763
30781
|
schemaClass2.genericParameters ?? [],
|
|
30764
30782
|
"schemaClass.genericParameters"
|
|
30765
30783
|
)) {
|
|
30784
|
+
const parameterId = string2(parameter4.id, "genericParameter.id");
|
|
30766
30785
|
genericNames.set(
|
|
30767
|
-
|
|
30786
|
+
parameterId,
|
|
30768
30787
|
string2(parameter4.name, "genericParameter.name")
|
|
30769
30788
|
);
|
|
30789
|
+
genericDeclarations.set(parameterId, parameter4);
|
|
30790
|
+
genericOwnerClassIds.set(parameterId, classId);
|
|
30770
30791
|
}
|
|
30771
30792
|
}
|
|
30772
30793
|
const rootMemberIds2 = options.rootMemberIds ?? inferRootMemberIds(members);
|
|
@@ -30777,6 +30798,8 @@ function projectSchemaManifest(input, options = {}) {
|
|
|
30777
30798
|
interfaces: interfaceById,
|
|
30778
30799
|
enums: indexById(enums, "ProjectSchemaManifest.enums"),
|
|
30779
30800
|
genericNames,
|
|
30801
|
+
genericDeclarations,
|
|
30802
|
+
genericOwnerClassIds,
|
|
30780
30803
|
effectiveWritabilityByMemberId: effectiveMemberWritability(
|
|
30781
30804
|
members,
|
|
30782
30805
|
classes,
|
|
@@ -31150,7 +31173,7 @@ function schemaClass(value, environment, field) {
|
|
|
31150
31173
|
return {
|
|
31151
31174
|
id: parameterId,
|
|
31152
31175
|
name,
|
|
31153
|
-
type:
|
|
31176
|
+
type: typeParameter(parameterId, environment, false),
|
|
31154
31177
|
...spanAndSelectionLocations(
|
|
31155
31178
|
parameter4.source,
|
|
31156
31179
|
parameter4.selectionSpan ?? parameter4.source,
|
|
@@ -32139,14 +32162,73 @@ function manifestPrimitive(kind) {
|
|
|
32139
32162
|
return null;
|
|
32140
32163
|
}
|
|
32141
32164
|
}
|
|
32142
|
-
function typeParameter(id2, environment, nullable) {
|
|
32165
|
+
function typeParameter(id2, environment, nullable, visiting = /* @__PURE__ */ new Set()) {
|
|
32166
|
+
const declaration = environment.genericDeclarations.get(id2);
|
|
32167
|
+
const constraint = declaration?.constraint;
|
|
32168
|
+
const next = new Set(visiting).add(id2);
|
|
32143
32169
|
return {
|
|
32144
32170
|
kind: "typeParameter",
|
|
32145
32171
|
id: id2,
|
|
32146
32172
|
name: environment.genericNames.get(id2) ?? id2,
|
|
32173
|
+
...environment.genericOwnerClassIds.has(id2) ? { ownerClassId: environment.genericOwnerClassIds.get(id2) } : {},
|
|
32174
|
+
...visiting.has(id2) || constraint === void 0 || constraint === null ? {} : {
|
|
32175
|
+
constraint: genericConstraintType(
|
|
32176
|
+
constraint,
|
|
32177
|
+
environment,
|
|
32178
|
+
next,
|
|
32179
|
+
`generic parameter ${id2}.constraint`
|
|
32180
|
+
)
|
|
32181
|
+
},
|
|
32147
32182
|
nullable
|
|
32148
32183
|
};
|
|
32149
32184
|
}
|
|
32185
|
+
function genericConstraintType(value, environment, visiting, field) {
|
|
32186
|
+
const constraint = record2(value, field);
|
|
32187
|
+
if (constraint.kind === "enum") {
|
|
32188
|
+
return {
|
|
32189
|
+
kind: "named",
|
|
32190
|
+
typeId: string2(constraint.enumId, `${field}.enumId`),
|
|
32191
|
+
nullable: false
|
|
32192
|
+
};
|
|
32193
|
+
}
|
|
32194
|
+
if (constraint.kind !== "class") {
|
|
32195
|
+
throw new Error(`${field}.kind must be "class" or "enum".`);
|
|
32196
|
+
}
|
|
32197
|
+
const classId = string2(constraint.classId, `${field}.classId`);
|
|
32198
|
+
const target = environment.classes.get(classId);
|
|
32199
|
+
const parameters = target ? records(target.genericParameters ?? [], `${field}.genericParameters`) : [];
|
|
32200
|
+
const bindings = optionalRecord(constraint.classArguments) ?? {};
|
|
32201
|
+
const typeArguments = parameters.flatMap((parameter4) => {
|
|
32202
|
+
const parameterId = string2(parameter4.id, `${field}.genericParameter.id`);
|
|
32203
|
+
const binding = optionalRecord(bindings[parameterId]);
|
|
32204
|
+
if (binding?.kind === "generic" && typeof binding.genericParamId === "string") {
|
|
32205
|
+
return [
|
|
32206
|
+
typeParameter(binding.genericParamId, environment, false, visiting)
|
|
32207
|
+
];
|
|
32208
|
+
}
|
|
32209
|
+
if (binding?.kind === "member" && typeof binding.memberId === "string") {
|
|
32210
|
+
const member = environment.members.get(binding.memberId);
|
|
32211
|
+
return member ? [
|
|
32212
|
+
{
|
|
32213
|
+
...memberType(
|
|
32214
|
+
member,
|
|
32215
|
+
environment,
|
|
32216
|
+
/* @__PURE__ */ new Set(),
|
|
32217
|
+
`${field}.classArguments.${parameterId}`
|
|
32218
|
+
),
|
|
32219
|
+
nullable: false
|
|
32220
|
+
}
|
|
32221
|
+
] : [];
|
|
32222
|
+
}
|
|
32223
|
+
return [];
|
|
32224
|
+
});
|
|
32225
|
+
return {
|
|
32226
|
+
kind: "named",
|
|
32227
|
+
typeId: classId,
|
|
32228
|
+
nullable: false,
|
|
32229
|
+
...typeArguments.length === parameters.length && typeArguments.length > 0 ? { typeArguments } : {}
|
|
32230
|
+
};
|
|
32231
|
+
}
|
|
32150
32232
|
function primitive(name, nullable) {
|
|
32151
32233
|
return { kind: "primitive", name, nullable };
|
|
32152
32234
|
}
|
|
@@ -34673,6 +34755,16 @@ function inferMemberOwners(classes, members) {
|
|
|
34673
34755
|
schemaClass2.recordId,
|
|
34674
34756
|
set
|
|
34675
34757
|
);
|
|
34758
|
+
if (Array.isArray(schemaClass2.data.genericParams)) {
|
|
34759
|
+
for (const parameterValue of schemaClass2.data.genericParams) {
|
|
34760
|
+
if (!isRecord2(parameterValue)) continue;
|
|
34761
|
+
const parameterId = parameterValue.id;
|
|
34762
|
+
const constraint = parameterValue.constraint;
|
|
34763
|
+
if (typeof parameterId !== "string" || !isRecord2(constraint)) continue;
|
|
34764
|
+
if (constraint.kind !== "class") continue;
|
|
34765
|
+
collectGenericOwners(constraint.classArguments, parameterId, set);
|
|
34766
|
+
}
|
|
34767
|
+
}
|
|
34676
34768
|
}
|
|
34677
34769
|
for (const [memberId, member] of members) {
|
|
34678
34770
|
if (typeof member.entryMemberId === "string") {
|
|
@@ -38073,8 +38165,19 @@ function assertGenericParameter(value, path) {
|
|
|
38073
38165
|
if (parameter4.constraint === null) return;
|
|
38074
38166
|
const constraint = requireRecord(parameter4.constraint, `${path}.constraint`);
|
|
38075
38167
|
if (constraint.kind === "class") {
|
|
38076
|
-
|
|
38168
|
+
knownKeysWithOptional(
|
|
38169
|
+
constraint,
|
|
38170
|
+
`${path}.constraint`,
|
|
38171
|
+
["kind", "classId"],
|
|
38172
|
+
["classArguments"]
|
|
38173
|
+
);
|
|
38077
38174
|
nonEmptyString(constraint.classId, `${path}.constraint.classId`);
|
|
38175
|
+
if (constraint.classArguments !== void 0 && constraint.classArguments !== null) {
|
|
38176
|
+
assertGenericBindingRecord(
|
|
38177
|
+
constraint.classArguments,
|
|
38178
|
+
`${path}.constraint.classArguments`
|
|
38179
|
+
);
|
|
38180
|
+
}
|
|
38078
38181
|
return;
|
|
38079
38182
|
}
|
|
38080
38183
|
if (constraint.kind === "enum") {
|
|
@@ -41812,7 +41915,9 @@ function isGenericParamConstraint(value) {
|
|
|
41812
41915
|
if (v.kind === "class") {
|
|
41813
41916
|
if (typeof v.classId !== "string") return false;
|
|
41814
41917
|
if (v.classId.length === 0) return false;
|
|
41815
|
-
|
|
41918
|
+
if (v.enumId !== void 0) return false;
|
|
41919
|
+
const argumentsValue = v.classArguments;
|
|
41920
|
+
return argumentsValue === void 0 || argumentsValue === null || isGenericBindingsRecord(argumentsValue);
|
|
41816
41921
|
}
|
|
41817
41922
|
if (v.kind === "enum") {
|
|
41818
41923
|
if (typeof v.enumId !== "string") return false;
|
|
@@ -49582,11 +49687,7 @@ function emitClass(context, schemaClass2, memberIds) {
|
|
|
49582
49687
|
const modifier = schemaClass2.isSealed ? "sealed " : schemaClass2.declarationModifier === "abstract" ? "abstract " : "";
|
|
49583
49688
|
const generics = schemaClass2.genericParameters.length ? `<
|
|
49584
49689
|
${schemaClass2.genericParameters.map((parameter4) => {
|
|
49585
|
-
const constraint = parameter4.constraint ? ` extends ${parameter4.constraint
|
|
49586
|
-
context.classes,
|
|
49587
|
-
parameter4.constraint.classId,
|
|
49588
|
-
"class"
|
|
49589
|
-
).name : required(context.enums, parameter4.constraint.enumId, "enum").name}` : "";
|
|
49690
|
+
const constraint = parameter4.constraint ? ` extends ${renderGenericConstraint(context, parameter4.constraint)}` : "";
|
|
49590
49691
|
return ` ${id(parameter4.id)} ${parameter4.name}${constraint}`;
|
|
49591
49692
|
}).join(",\n")}
|
|
49592
49693
|
>` : "";
|
|
@@ -49660,6 +49761,31 @@ ${members.join("\n\n")}
|
|
|
49660
49761
|
}
|
|
49661
49762
|
`;
|
|
49662
49763
|
}
|
|
49764
|
+
function renderGenericConstraint(context, constraint) {
|
|
49765
|
+
if (constraint.kind === "enum") {
|
|
49766
|
+
return required(context.enums, constraint.enumId, "enum").name;
|
|
49767
|
+
}
|
|
49768
|
+
const target = required(context.classes, constraint.classId, "class");
|
|
49769
|
+
if (target.genericParameters.length === 0) return target.name;
|
|
49770
|
+
const bindings = constraint.classArguments;
|
|
49771
|
+
if (bindings === void 0 || bindings === null) return target.name;
|
|
49772
|
+
const argumentsValue = target.genericParameters.map((parameter4) => {
|
|
49773
|
+
const binding = bindings[parameter4.id];
|
|
49774
|
+
if (binding === void 0) {
|
|
49775
|
+
throw new Error(
|
|
49776
|
+
`Generic constraint ${target.name} is missing its argument for ${parameter4.name}.`
|
|
49777
|
+
);
|
|
49778
|
+
}
|
|
49779
|
+
if (binding.kind === "generic") {
|
|
49780
|
+
return genericName(context, binding.genericParamId);
|
|
49781
|
+
}
|
|
49782
|
+
return renderMemberType(
|
|
49783
|
+
context,
|
|
49784
|
+
required(context.members, binding.memberId, "generic constraint binding")
|
|
49785
|
+
).replace(/\?$/u, "");
|
|
49786
|
+
});
|
|
49787
|
+
return `${target.name}<${argumentsValue.join(", ")}>`;
|
|
49788
|
+
}
|
|
49663
49789
|
function baseConstruction(requiredConstructor) {
|
|
49664
49790
|
if (requiredConstructor === void 0) return "";
|
|
49665
49791
|
const args = requiredConstructor.baseArguments ?? [];
|
|
@@ -56139,7 +56265,15 @@ function lowerClass(context, declaration) {
|
|
|
56139
56265
|
return {
|
|
56140
56266
|
id: parameterId,
|
|
56141
56267
|
name: parameter4.name,
|
|
56142
|
-
constraint: parameter4.constraint ? genericConstraint(
|
|
56268
|
+
constraint: parameter4.constraint ? genericConstraint(
|
|
56269
|
+
context,
|
|
56270
|
+
declaration,
|
|
56271
|
+
parameterId,
|
|
56272
|
+
parameter4.constraint,
|
|
56273
|
+
base?.genericParameters.find(
|
|
56274
|
+
(candidate) => candidate.id === parameterId
|
|
56275
|
+
)?.constraint
|
|
56276
|
+
) : null,
|
|
56143
56277
|
source: span(parameter4.identity),
|
|
56144
56278
|
selectionSpan: span(parameter4.identity)
|
|
56145
56279
|
};
|
|
@@ -58090,9 +58224,22 @@ function lowerGenericArgument(context, ownerClass, type, memberId, genericParamI
|
|
|
58090
58224
|
)
|
|
58091
58225
|
);
|
|
58092
58226
|
}
|
|
58093
|
-
function genericConstraint(context, type) {
|
|
58227
|
+
function genericConstraint(context, ownerClass, parameterId, type, baseConstraint) {
|
|
58094
58228
|
const classId = context.classIdsByName.get(type.name);
|
|
58095
|
-
if (classId)
|
|
58229
|
+
if (classId) {
|
|
58230
|
+
const classArguments2 = type.arguments.length === 0 ? void 0 : lowerClassArguments(
|
|
58231
|
+
context,
|
|
58232
|
+
ownerClass,
|
|
58233
|
+
parameterId,
|
|
58234
|
+
type,
|
|
58235
|
+
baseConstraint?.kind === "class" ? baseConstraint.classArguments ?? void 0 : void 0
|
|
58236
|
+
);
|
|
58237
|
+
return {
|
|
58238
|
+
kind: "class",
|
|
58239
|
+
classId,
|
|
58240
|
+
...classArguments2 === void 0 ? {} : { classArguments: classArguments2 }
|
|
58241
|
+
};
|
|
58242
|
+
}
|
|
58096
58243
|
return {
|
|
58097
58244
|
kind: "enum",
|
|
58098
58245
|
enumId: requiredName2(context.enumIdsByName, type.name, "enum")
|
|
@@ -58998,18 +59145,12 @@ function classToLanguageType(schemaClass2, context) {
|
|
|
58998
59145
|
typeParameters: schemaClass2.genericParams.map((parameter4) => ({
|
|
58999
59146
|
id: parameter4.id,
|
|
59000
59147
|
name: parameter4.name,
|
|
59001
|
-
type:
|
|
59002
|
-
|
|
59003
|
-
|
|
59004
|
-
|
|
59005
|
-
|
|
59006
|
-
|
|
59007
|
-
constraint: namedType(
|
|
59008
|
-
parameter4.constraint.kind === "class" ? parameter4.constraint.classId : parameter4.constraint.enumId,
|
|
59009
|
-
true
|
|
59010
|
-
)
|
|
59011
|
-
}
|
|
59012
|
-
},
|
|
59148
|
+
type: genericParameterLanguageType(
|
|
59149
|
+
parameter4.id,
|
|
59150
|
+
true,
|
|
59151
|
+
context,
|
|
59152
|
+
genericEnvironment
|
|
59153
|
+
),
|
|
59013
59154
|
location: virtualIdentifierLocation(
|
|
59014
59155
|
context,
|
|
59015
59156
|
"Classes",
|
|
@@ -59659,31 +59800,12 @@ function memberRuntimeType(record3, context, seen = /* @__PURE__ */ new Set(), g
|
|
|
59659
59800
|
);
|
|
59660
59801
|
}
|
|
59661
59802
|
}
|
|
59662
|
-
|
|
59663
|
-
|
|
59664
|
-
|
|
59665
|
-
|
|
59666
|
-
|
|
59667
|
-
|
|
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
|
-
};
|
|
59803
|
+
return genericParameterLanguageType(
|
|
59804
|
+
genericParamId,
|
|
59805
|
+
required2,
|
|
59806
|
+
context,
|
|
59807
|
+
genericEnvironment
|
|
59808
|
+
);
|
|
59687
59809
|
}
|
|
59688
59810
|
case 27 /* Variant */: {
|
|
59689
59811
|
if (!isMemberVariantBase(member)) return UNKNOWN_TYPE2;
|
|
@@ -59746,13 +59868,13 @@ function classArguments(member, context, seen, genericEnvironment) {
|
|
|
59746
59868
|
)
|
|
59747
59869
|
] : [];
|
|
59748
59870
|
}
|
|
59749
|
-
const declaration = context.vm.classes.flatMap((schemaClass2) => schemaClass2.genericParams ?? []).find((candidate) => candidate.id === binding.genericParamId);
|
|
59750
59871
|
return [
|
|
59751
|
-
|
|
59752
|
-
|
|
59753
|
-
|
|
59754
|
-
|
|
59755
|
-
|
|
59872
|
+
genericParameterLanguageType(
|
|
59873
|
+
binding.genericParamId,
|
|
59874
|
+
true,
|
|
59875
|
+
context,
|
|
59876
|
+
genericEnvironment
|
|
59877
|
+
)
|
|
59756
59878
|
];
|
|
59757
59879
|
}
|
|
59758
59880
|
const argument2 = analyzerMemberById(context.vm, binding.memberId);
|
|
@@ -59900,33 +60022,89 @@ function toLanguageType(type, context, genericEnvironment) {
|
|
|
59900
60022
|
);
|
|
59901
60023
|
}
|
|
59902
60024
|
}
|
|
59903
|
-
|
|
59904
|
-
|
|
59905
|
-
|
|
59906
|
-
|
|
59907
|
-
|
|
60025
|
+
return genericParameterLanguageType(
|
|
60026
|
+
environmentEntry?.kind === "unbound" ? environmentEntry.paramId : type.genericParamId,
|
|
60027
|
+
required2,
|
|
60028
|
+
context,
|
|
60029
|
+
genericEnvironment
|
|
59908
60030
|
);
|
|
59909
|
-
|
|
59910
|
-
|
|
59911
|
-
|
|
59912
|
-
|
|
59913
|
-
|
|
60031
|
+
}
|
|
60032
|
+
}
|
|
60033
|
+
}
|
|
60034
|
+
function genericParameterLanguageType(genericParamId, required2, context, genericEnvironment, visiting = /* @__PURE__ */ new Set()) {
|
|
60035
|
+
const environmentEntry = genericEnvironment?.get(genericParamId);
|
|
60036
|
+
if (environmentEntry?.kind === "member") {
|
|
60037
|
+
const binding = analyzerMemberById(context.vm, environmentEntry.memberId);
|
|
60038
|
+
if (binding) {
|
|
60039
|
+
return requiredType(
|
|
60040
|
+
memberRuntimeType(binding, context, /* @__PURE__ */ new Set(), genericEnvironment)
|
|
59914
60041
|
);
|
|
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
60042
|
}
|
|
59929
60043
|
}
|
|
60044
|
+
const effectiveParamId = environmentEntry?.kind === "unbound" ? environmentEntry.paramId : genericParamId;
|
|
60045
|
+
const owner = context.vm.classes.find(
|
|
60046
|
+
(schemaClass2) => schemaClass2.genericParams?.some(
|
|
60047
|
+
(parameter4) => parameter4.id === effectiveParamId
|
|
60048
|
+
)
|
|
60049
|
+
);
|
|
60050
|
+
const declaration = owner?.genericParams?.find(
|
|
60051
|
+
(parameter4) => parameter4.id === effectiveParamId
|
|
60052
|
+
);
|
|
60053
|
+
const next = new Set(visiting).add(effectiveParamId);
|
|
60054
|
+
return {
|
|
60055
|
+
kind: "typeParameter",
|
|
60056
|
+
id: effectiveParamId,
|
|
60057
|
+
name: declaration?.name ?? effectiveParamId,
|
|
60058
|
+
...owner === void 0 ? {} : { ownerClassId: owner.id },
|
|
60059
|
+
...visiting.has(effectiveParamId) || declaration?.constraint == null ? {} : {
|
|
60060
|
+
constraint: genericConstraintLanguageType(
|
|
60061
|
+
declaration.constraint,
|
|
60062
|
+
context,
|
|
60063
|
+
genericEnvironment,
|
|
60064
|
+
next
|
|
60065
|
+
)
|
|
60066
|
+
},
|
|
60067
|
+
nullable: !required2
|
|
60068
|
+
};
|
|
60069
|
+
}
|
|
60070
|
+
function genericConstraintLanguageType(constraint, context, genericEnvironment, visiting = /* @__PURE__ */ new Set()) {
|
|
60071
|
+
if (constraint.kind === "enum") {
|
|
60072
|
+
return namedType(constraint.enumId, true);
|
|
60073
|
+
}
|
|
60074
|
+
const target = context.vm.classes.find(
|
|
60075
|
+
(schemaClass2) => schemaClass2.id === constraint.classId
|
|
60076
|
+
);
|
|
60077
|
+
const bindings = constraint.classArguments;
|
|
60078
|
+
if (!target?.genericParams?.length || bindings == null) {
|
|
60079
|
+
return namedType(constraint.classId, true);
|
|
60080
|
+
}
|
|
60081
|
+
const typeArguments = target.genericParams.flatMap((parameter4) => {
|
|
60082
|
+
const binding = bindings[parameter4.id];
|
|
60083
|
+
if (binding === void 0) return [];
|
|
60084
|
+
if (binding.kind === "generic") {
|
|
60085
|
+
return [
|
|
60086
|
+
genericParameterLanguageType(
|
|
60087
|
+
binding.genericParamId,
|
|
60088
|
+
true,
|
|
60089
|
+
context,
|
|
60090
|
+
genericEnvironment,
|
|
60091
|
+
visiting
|
|
60092
|
+
)
|
|
60093
|
+
];
|
|
60094
|
+
}
|
|
60095
|
+
const member = analyzerMemberById(context.vm, binding.memberId);
|
|
60096
|
+
return member ? [
|
|
60097
|
+
requiredType(
|
|
60098
|
+
memberRuntimeType(member, context, /* @__PURE__ */ new Set(), genericEnvironment)
|
|
60099
|
+
)
|
|
60100
|
+
] : [];
|
|
60101
|
+
});
|
|
60102
|
+
return {
|
|
60103
|
+
kind: "named",
|
|
60104
|
+
typeId: constraint.classId,
|
|
60105
|
+
nullable: false,
|
|
60106
|
+
...typeArguments.length === target.genericParams.length ? { typeArguments } : {}
|
|
60107
|
+
};
|
|
59930
60108
|
}
|
|
59931
60109
|
function functionReturnType(type, context, genericEnvironment) {
|
|
59932
60110
|
return type.type === NS_TYPE_VOID ? primitive2("void", true) : toLanguageType(type, context, genericEnvironment);
|
|
@@ -60094,12 +60272,68 @@ function virtualNeoSchemaClassHeader(schemaClass2, context) {
|
|
|
60094
60272
|
)?.name ?? constraint.classId : context.vm.enums.find(
|
|
60095
60273
|
(candidate) => candidate.id === constraint.enumId
|
|
60096
60274
|
)?.name ?? constraint.enumId;
|
|
60275
|
+
const targetClass = constraint.kind === "class" ? context.vm.classes.find(
|
|
60276
|
+
(candidate) => candidate.id === constraint.classId
|
|
60277
|
+
) : void 0;
|
|
60278
|
+
const bindings = constraint.kind === "class" ? constraint.classArguments : void 0;
|
|
60279
|
+
const argumentsValue = targetClass?.genericParams?.flatMap(
|
|
60280
|
+
(targetParameter) => {
|
|
60281
|
+
const binding = bindings?.[targetParameter.id];
|
|
60282
|
+
if (binding?.kind === "generic") {
|
|
60283
|
+
const declaration = context.vm.classes.flatMap((candidate) => candidate.genericParams ?? []).find((candidate) => candidate.id === binding.genericParamId);
|
|
60284
|
+
return [
|
|
60285
|
+
virtualCSharpIdentifier(
|
|
60286
|
+
declaration?.name ?? binding.genericParamId
|
|
60287
|
+
)
|
|
60288
|
+
];
|
|
60289
|
+
}
|
|
60290
|
+
if (binding?.kind === "member") {
|
|
60291
|
+
const member = analyzerMemberById(context.vm, binding.memberId);
|
|
60292
|
+
return [
|
|
60293
|
+
member ? virtualConstraintMemberType(member, context) : "object"
|
|
60294
|
+
];
|
|
60295
|
+
}
|
|
60296
|
+
return [];
|
|
60297
|
+
}
|
|
60298
|
+
);
|
|
60299
|
+
const argumentSuffix = targetClass?.genericParams?.length && argumentsValue?.length === targetClass.genericParams.length ? `<${argumentsValue.join(", ")}>` : "";
|
|
60097
60300
|
return [
|
|
60098
|
-
` where ${virtualCSharpIdentifier(parameter4.name)} : ${virtualCSharpIdentifier(target)}`
|
|
60301
|
+
` where ${virtualCSharpIdentifier(parameter4.name)} : ${virtualCSharpIdentifier(target)}${argumentSuffix}`
|
|
60099
60302
|
];
|
|
60100
60303
|
});
|
|
60101
60304
|
return `public ${schemaClass2.isAbstract ? "abstract " : ""}partial class ${virtualCSharpIdentifier(schemaClass2.name)}${genericParameters}${inheritance}${constraints.join("")} // Neo class ${schemaClass2.id}`;
|
|
60102
60305
|
}
|
|
60306
|
+
function virtualConstraintMemberType(member, context) {
|
|
60307
|
+
const resolved = resolveMember2(member, context.vm.members);
|
|
60308
|
+
switch (resolved.kind) {
|
|
60309
|
+
case 1 /* Bool */:
|
|
60310
|
+
return "bool";
|
|
60311
|
+
case 2 /* Int */:
|
|
60312
|
+
return "int";
|
|
60313
|
+
case 3 /* String */:
|
|
60314
|
+
return "string";
|
|
60315
|
+
case 4 /* Float */:
|
|
60316
|
+
return "double";
|
|
60317
|
+
case 20 /* Decimal */:
|
|
60318
|
+
return "decimal";
|
|
60319
|
+
case 7 /* Class */: {
|
|
60320
|
+
const classId = getOptionalString(resolved, "classId");
|
|
60321
|
+
const schemaClass2 = context.vm.classes.find(
|
|
60322
|
+
(candidate) => candidate.id === classId
|
|
60323
|
+
);
|
|
60324
|
+
return virtualCSharpIdentifier(schemaClass2?.name ?? classId ?? "object");
|
|
60325
|
+
}
|
|
60326
|
+
case 8 /* Enum */: {
|
|
60327
|
+
const enumId = getOptionalString(resolved, "enumId");
|
|
60328
|
+
const neoEnum = context.vm.enums.find(
|
|
60329
|
+
(candidate) => candidate.id === enumId
|
|
60330
|
+
);
|
|
60331
|
+
return virtualCSharpIdentifier(neoEnum?.name ?? enumId ?? "object");
|
|
60332
|
+
}
|
|
60333
|
+
default:
|
|
60334
|
+
return "object";
|
|
60335
|
+
}
|
|
60336
|
+
}
|
|
60103
60337
|
function virtualNeoSchemaClassMemberLine(schemaKey, displayName, memberId) {
|
|
60104
60338
|
return ` public object? ${virtualCSharpIdentifier(schemaKey)} { get; init; } // ${displayName}; Neo member ${memberId}`;
|
|
60105
60339
|
}
|
|
@@ -60135,7 +60369,7 @@ var init_neoscript_language_context_adapter = __esm({
|
|
|
60135
60369
|
init_project_root_members();
|
|
60136
60370
|
init_project_file_registry();
|
|
60137
60371
|
init_analyzer_types();
|
|
60138
|
-
NEOSCRIPT_COMPILER_ADAPTER_REVISION =
|
|
60372
|
+
NEOSCRIPT_COMPILER_ADAPTER_REVISION = 2;
|
|
60139
60373
|
UNKNOWN_TYPE2 = {
|
|
60140
60374
|
kind: "primitive",
|
|
60141
60375
|
name: "unknown"
|
|
@@ -82237,10 +82471,13 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
|
|
|
82237
82471
|
`Class "${schemaClass2.name}" (${schemaClass2.id}) cannot extend sealed class "${baseClass.name}" (${baseClass.id}).`
|
|
82238
82472
|
);
|
|
82239
82473
|
}
|
|
82240
|
-
const
|
|
82474
|
+
const genericParamDeclarationsById = new Map(
|
|
82241
82475
|
classes.flatMap(
|
|
82242
82476
|
(schemaClass2) => (schemaClass2.genericParams ?? []).map(
|
|
82243
|
-
(param) => [
|
|
82477
|
+
(param) => [
|
|
82478
|
+
param.id,
|
|
82479
|
+
{ constraint: param.constraint, ownerClassId: schemaClass2.id }
|
|
82480
|
+
]
|
|
82244
82481
|
)
|
|
82245
82482
|
)
|
|
82246
82483
|
);
|
|
@@ -83155,13 +83392,40 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
|
|
|
83155
83392
|
if (!isRecord7(typeInfo) || typeInfo.type !== 21 || typeof typeInfo.genericParamId !== "string") {
|
|
83156
83393
|
return null;
|
|
83157
83394
|
}
|
|
83158
|
-
const constraint =
|
|
83395
|
+
const constraint = genericParamDeclarationsById.get(
|
|
83396
|
+
typeInfo.genericParamId
|
|
83397
|
+
)?.constraint;
|
|
83159
83398
|
if (!constraint) return null;
|
|
83160
|
-
|
|
83161
|
-
|
|
83162
|
-
|
|
83163
|
-
|
|
83164
|
-
|
|
83399
|
+
if (constraint.kind === "class") {
|
|
83400
|
+
const typeArguments = Object.fromEntries(
|
|
83401
|
+
Object.entries(constraint.classArguments ?? {}).flatMap(
|
|
83402
|
+
([parameterId, binding]) => {
|
|
83403
|
+
if (binding.kind !== "generic") return [];
|
|
83404
|
+
const ownerClassId = genericParamDeclarationsById.get(
|
|
83405
|
+
binding.genericParamId
|
|
83406
|
+
)?.ownerClassId;
|
|
83407
|
+
return ownerClassId === void 0 ? [] : [
|
|
83408
|
+
[
|
|
83409
|
+
parameterId,
|
|
83410
|
+
{
|
|
83411
|
+
type: 21,
|
|
83412
|
+
required: true,
|
|
83413
|
+
ownerClassId,
|
|
83414
|
+
genericParamId: binding.genericParamId
|
|
83415
|
+
}
|
|
83416
|
+
]
|
|
83417
|
+
];
|
|
83418
|
+
}
|
|
83419
|
+
)
|
|
83420
|
+
);
|
|
83421
|
+
return {
|
|
83422
|
+
type: 7,
|
|
83423
|
+
required: typeInfo.required === true,
|
|
83424
|
+
classId: constraint.classId,
|
|
83425
|
+
...Object.keys(typeArguments).length > 0 ? { typeArguments } : {}
|
|
83426
|
+
};
|
|
83427
|
+
}
|
|
83428
|
+
return {
|
|
83165
83429
|
type: 8,
|
|
83166
83430
|
required: typeInfo.required === true,
|
|
83167
83431
|
enumId: constraint.enumId
|
|
@@ -111011,8 +111275,8 @@ var init_registry2 = __esm({
|
|
|
111011
111275
|
"use strict";
|
|
111012
111276
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
111013
111277
|
formatVersion: 3,
|
|
111014
|
-
contractVersion: "3.
|
|
111015
|
-
cliVersion: "0.31.
|
|
111278
|
+
contractVersion: "3.13",
|
|
111279
|
+
cliVersion: "0.31.8",
|
|
111016
111280
|
projectFileUploadBatchSize: 32,
|
|
111017
111281
|
documentRecords: {
|
|
111018
111282
|
member: {
|
|
@@ -117607,7 +117871,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
117607
117871
|
async function main() {
|
|
117608
117872
|
const args = parseArgs(process.argv.slice(2));
|
|
117609
117873
|
if (args.command === "--version") {
|
|
117610
|
-
console.log("0.31.
|
|
117874
|
+
console.log("0.31.8");
|
|
117611
117875
|
return;
|
|
117612
117876
|
}
|
|
117613
117877
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
package/package.json
CHANGED
|
@@ -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.
|
|
86
|
+
<!-- reviewed-through-cli: 0.31.8 -->
|
|
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
|
+
```
|
|
@@ -49,6 +49,11 @@ if (player.Target != null) {
|
|
|
49
49
|
return player.Target?.Name ?? "Unknown";
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
Null propagation remains active across following required accesses in the same
|
|
53
|
+
chain, so `config.Hat?.Head.Idle.Down.Frames` safely returns null when `Hat` is
|
|
54
|
+
null. A descendant that is itself nullable still needs its own `?.`, `??`, `!`,
|
|
55
|
+
or narrowing guard before the next access.
|
|
56
|
+
|
|
52
57
|
Treat lookup-return values with the same nullable narrowing rules.
|
|
53
58
|
|
|
54
59
|
Let runtime ownership—not body kind—decide whether a write target is Immutable,
|