@neocompose/cli 0.76.0 → 0.76.2

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.
@@ -1936,6 +1936,7 @@ var NEOSCRIPT_OPERATORS = [
1936
1936
  var STRING_TYPE2 = { kind: "primitive", name: "string" };
1937
1937
  var INT_TYPE2 = { kind: "primitive", name: "int" };
1938
1938
  var FLOAT_TYPE = { kind: "primitive", name: "float" };
1939
+ var DECIMAL_TYPE = { kind: "primitive", name: "decimal" };
1939
1940
  var BOOL_TYPE2 = { kind: "primitive", name: "bool" };
1940
1941
  var IMAGE_REF_TYPE = {
1941
1942
  kind: "primitive",
@@ -1945,6 +1946,7 @@ var SPRITE_INFO_TYPE = {
1945
1946
  kind: "primitive",
1946
1947
  name: "SpriteInfo"
1947
1948
  };
1949
+ var VECTOR2_TYPE = { kind: "primitive", name: "Vector2" };
1948
1950
  var FLOAT_OPTIONAL_TYPE = {
1949
1951
  kind: "primitive",
1950
1952
  name: "float",
@@ -2123,6 +2125,156 @@ var NEOSCRIPT_GLOBALS = [
2123
2125
  "Returns whether a dialogue pointer has been visited."
2124
2126
  )
2125
2127
  ];
2128
+ function scalarMethod(receiver, name, returnType, parameters, documentation) {
2129
+ return {
2130
+ id: `builtin:${receiver}:${name}`,
2131
+ name,
2132
+ kind: "method",
2133
+ type: returnType,
2134
+ returnType,
2135
+ parameters,
2136
+ documentation
2137
+ };
2138
+ }
2139
+ var NEOSCRIPT_SCALAR_METHODS = {
2140
+ string: [
2141
+ scalarMethod(
2142
+ "string",
2143
+ "Contains",
2144
+ BOOL_TYPE2,
2145
+ [parameter("substring", STRING_TYPE2)],
2146
+ "Returns true when the string contains the substring."
2147
+ ),
2148
+ scalarMethod(
2149
+ "string",
2150
+ "Replace",
2151
+ STRING_TYPE2,
2152
+ [parameter("search", STRING_TYPE2), parameter("replacement", STRING_TYPE2)],
2153
+ "Returns a new string with every non-overlapping occurrence replaced using ordinal, case-sensitive matching. An empty search throws an error."
2154
+ ),
2155
+ scalarMethod(
2156
+ "string",
2157
+ "ToLower",
2158
+ STRING_TYPE2,
2159
+ [],
2160
+ "Returns the string converted to lowercase."
2161
+ ),
2162
+ scalarMethod(
2163
+ "string",
2164
+ "ToUpper",
2165
+ STRING_TYPE2,
2166
+ [],
2167
+ "Returns the string converted to uppercase."
2168
+ ),
2169
+ scalarMethod(
2170
+ "string",
2171
+ "Trim",
2172
+ STRING_TYPE2,
2173
+ [],
2174
+ "Returns the string without leading and trailing whitespace."
2175
+ ),
2176
+ scalarMethod(
2177
+ "string",
2178
+ "StartsWith",
2179
+ BOOL_TYPE2,
2180
+ [parameter("prefix", STRING_TYPE2)],
2181
+ "Returns true when the string starts with the prefix."
2182
+ ),
2183
+ scalarMethod(
2184
+ "string",
2185
+ "EndsWith",
2186
+ BOOL_TYPE2,
2187
+ [parameter("suffix", STRING_TYPE2)],
2188
+ "Returns true when the string ends with the suffix."
2189
+ )
2190
+ ],
2191
+ decimal: [
2192
+ scalarMethod(
2193
+ "decimal",
2194
+ "ToFloat",
2195
+ FLOAT_TYPE,
2196
+ [],
2197
+ "Returns the nearest float to this decimal."
2198
+ ),
2199
+ scalarMethod(
2200
+ "decimal",
2201
+ "Round",
2202
+ DECIMAL_TYPE,
2203
+ [parameter("digits", INT_TYPE2)],
2204
+ "Returns this decimal rounded half-to-even to the given number of fractional digits."
2205
+ ),
2206
+ scalarMethod(
2207
+ "decimal",
2208
+ "Divide",
2209
+ DECIMAL_TYPE,
2210
+ [parameter("divisor", DECIMAL_TYPE), parameter("digits", INT_TYPE2)],
2211
+ "Returns this decimal divided by the divisor, rounded half-to-even to the given number of fractional digits."
2212
+ )
2213
+ ],
2214
+ float: [
2215
+ scalarMethod(
2216
+ "float",
2217
+ "ToDecimal",
2218
+ DECIMAL_TYPE,
2219
+ [parameter("digits", INT_TYPE2)],
2220
+ "Returns this float as a decimal with the given number of fractional digits."
2221
+ )
2222
+ ],
2223
+ ImageRef: [
2224
+ scalarMethod(
2225
+ "ImageRef",
2226
+ "Slice",
2227
+ SPRITE_INFO_TYPE,
2228
+ [parameter("index", INT_TYPE2)],
2229
+ "Returns the sprite at the given slice index of this image."
2230
+ )
2231
+ ]
2232
+ };
2233
+ var NEOSCRIPT_CLASS_ID_MEMBER = "Id";
2234
+ var NEOSCRIPT_ON_CHANGED_MEMBER = "OnChanged";
2235
+ var NEOSCRIPT_CLASS_ID_SYMBOL = property(
2236
+ "class",
2237
+ NEOSCRIPT_CLASS_ID_MEMBER,
2238
+ STRING_TYPE2,
2239
+ "The stable id of this class value."
2240
+ );
2241
+ function neoScriptScalarMethod(receiver, name) {
2242
+ return NEOSCRIPT_SCALAR_METHODS[receiver]?.find(
2243
+ (method2) => method2.name === name
2244
+ );
2245
+ }
2246
+ var NEOSCRIPT_PRIMITIVE_DERIVED_MEMBERS = {
2247
+ SpriteInfo: [
2248
+ property("SpriteInfo", "FileName", STRING_TYPE2, "Asset file name."),
2249
+ property("SpriteInfo", "Name", STRING_TYPE2, "Sprite name."),
2250
+ property("SpriteInfo", "Size", VECTOR2_TYPE, "Sprite size."),
2251
+ property("SpriteInfo", "Pivot", VECTOR2_TYPE, "Sprite pivot."),
2252
+ property(
2253
+ "SpriteInfo",
2254
+ "Slices",
2255
+ { kind: "list", elementType: SPRITE_INFO_TYPE, readOnly: true },
2256
+ "All slices in the source asset."
2257
+ )
2258
+ ],
2259
+ AudioClipInfo: [
2260
+ property("AudioClipInfo", "FileId", STRING_TYPE2, "Asset file id."),
2261
+ property("AudioClipInfo", "Name", STRING_TYPE2, "Audio clip name."),
2262
+ property(
2263
+ "AudioClipInfo",
2264
+ "DurationSeconds",
2265
+ FLOAT_OPTIONAL_TYPE,
2266
+ "Audio duration in seconds when known."
2267
+ )
2268
+ ],
2269
+ NeoDialogueReference: [
2270
+ property("NeoDialogueReference", "id", STRING_TYPE2, "Dialogue id.")
2271
+ ]
2272
+ };
2273
+ function neoScriptPrimitiveDerivedMember(receiver, name) {
2274
+ return NEOSCRIPT_PRIMITIVE_DERIVED_MEMBERS[receiver]?.find(
2275
+ (member) => member.name === name
2276
+ );
2277
+ }
2126
2278
  function property(owner, name, type, documentation, writable = false) {
2127
2279
  return {
2128
2280
  id: `builtin:${owner}:property:${name}`,
@@ -2187,53 +2339,21 @@ var NEOSCRIPT_BUILTIN_TYPE_SYMBOLS = [
2187
2339
  // `FileId` and `SliceIndex` come from the field table above — they are
2188
2340
  // the writable, addressable fields, not derived properties (D11).
2189
2341
  ...structuredLeafFieldProperties("SpriteInfo"),
2190
- property("SpriteInfo", "FileName", STRING_TYPE2, "Asset file name."),
2191
- property("SpriteInfo", "Name", STRING_TYPE2, "Sprite name."),
2192
- property(
2193
- "SpriteInfo",
2194
- "Size",
2195
- { kind: "named", typeId: "builtin:Vector2" },
2196
- "Sprite size."
2197
- ),
2198
- property(
2199
- "SpriteInfo",
2200
- "Pivot",
2201
- { kind: "named", typeId: "builtin:Vector2" },
2202
- "Sprite pivot."
2203
- ),
2204
- property(
2205
- "SpriteInfo",
2206
- "Slices",
2207
- {
2208
- kind: "list",
2209
- elementType: { kind: "named", typeId: "builtin:SpriteInfo" },
2210
- readOnly: true
2211
- },
2212
- "All slices in the source asset."
2213
- )
2342
+ ...NEOSCRIPT_PRIMITIVE_DERIVED_MEMBERS.SpriteInfo
2214
2343
  ]
2215
2344
  },
2216
2345
  {
2217
2346
  id: "builtin:AudioClipInfo",
2218
2347
  name: "AudioClipInfo",
2219
2348
  kind: "builtin",
2220
- members: [
2221
- property("AudioClipInfo", "FileId", STRING_TYPE2, "Asset file id."),
2222
- property("AudioClipInfo", "Name", STRING_TYPE2, "Audio clip name."),
2223
- property(
2224
- "AudioClipInfo",
2225
- "DurationSeconds",
2226
- FLOAT_OPTIONAL_TYPE,
2227
- "Audio duration in seconds when known."
2228
- )
2229
- ]
2349
+ members: NEOSCRIPT_PRIMITIVE_DERIVED_MEMBERS.AudioClipInfo
2230
2350
  },
2231
2351
  {
2232
2352
  id: "builtin:NeoDialogueReference",
2233
2353
  name: "NeoDialogueReference",
2234
2354
  kind: "builtin",
2235
2355
  members: [
2236
- property("NeoDialogueReference", "id", STRING_TYPE2, "Dialogue id."),
2356
+ ...NEOSCRIPT_PRIMITIVE_DERIVED_MEMBERS.NeoDialogueReference,
2237
2357
  ...neoScriptDialogueReferenceMethods("builtin:NeoDialogueReference")
2238
2358
  ]
2239
2359
  },
@@ -5295,6 +5415,9 @@ var ProjectSchemaIndex = class {
5295
5415
  for (const schemaClass2 of source.classes) {
5296
5416
  this.classesById.set(schemaClass2.id, schemaClass2);
5297
5417
  append(this.classesByName, schemaClass2.name, schemaClass2);
5418
+ if (schemaClass2.extendsClassId) {
5419
+ append(this.subclassesById, schemaClass2.extendsClassId, schemaClass2);
5420
+ }
5298
5421
  for (const [schemaKey, memberId] of Object.entries(schemaClass2.schema)) {
5299
5422
  append(this.schemaPlacementsByMemberId, memberId, {
5300
5423
  ownerClass: schemaClass2,
@@ -5339,6 +5462,8 @@ var ProjectSchemaIndex = class {
5339
5462
  source;
5340
5463
  classesById = /* @__PURE__ */ new Map();
5341
5464
  classesByName = /* @__PURE__ */ new Map();
5465
+ /** Direct subclasses by the class they extend. */
5466
+ subclassesById = /* @__PURE__ */ new Map();
5342
5467
  membersById = /* @__PURE__ */ new Map();
5343
5468
  membersByName = /* @__PURE__ */ new Map();
5344
5469
  enumsById = /* @__PURE__ */ new Map();
@@ -5523,6 +5648,9 @@ function indexSchema(classes, members) {
5523
5648
  function classIndexFor(classes) {
5524
5649
  return indexClasses(classes).classesById;
5525
5650
  }
5651
+ function subclassIndexFor(classes) {
5652
+ return indexClasses(classes).subclassesById;
5653
+ }
5526
5654
  function memberIndexFor(members) {
5527
5655
  return projectSchemaIndexFor({ classes: NO_CLASSES, members }).membersById;
5528
5656
  }
@@ -5724,15 +5852,7 @@ function resolveMemberWithIndex(member, memberIndex) {
5724
5852
  return Object.freeze(merged);
5725
5853
  }
5726
5854
  function descendantClassIds(classId, allClasses) {
5727
- const childrenByClassId = /* @__PURE__ */ new Map();
5728
- for (const schemaClass2 of allClasses) {
5729
- if (!schemaClass2.extendsClassId) continue;
5730
- const children = childrenByClassId.get(schemaClass2.extendsClassId);
5731
- if (children === void 0) {
5732
- childrenByClassId.set(schemaClass2.extendsClassId, [schemaClass2]);
5733
- } else children.push(schemaClass2);
5734
- }
5735
- return descendantClassIdsInChildIndex(classId, childrenByClassId);
5855
+ return descendantClassIdsInChildIndex(classId, subclassIndexFor(allClasses));
5736
5856
  }
5737
5857
  function descendantClassIdsInChildIndex(classId, childrenByClassId) {
5738
5858
  const result = /* @__PURE__ */ new Set();
@@ -10667,103 +10787,204 @@ function buildDefaultClassMaterializationPlan(document2, classId, instanceEnv) {
10667
10787
  ...document2,
10668
10788
  constructors: document2.constructors ?? []
10669
10789
  });
10670
- const merged = document2.storedInstanceSchema?.(classId) ?? mergeInstanceSurfaceSchema(classId, document2.classes, document2.members);
10671
- return merged.flatMap((entry) => {
10672
- if (entry.memberId === null) return [];
10673
- const childMember = findMemberInDocument(document2, entry.memberId);
10674
- if (!memberKindOwnsStoredValue(childMember.kind)) return [];
10675
- if (instanceEnv.size === 0 && isImmutableConstantMember(
10676
- document2,
10677
- document2.resolvedMember?.(childMember) ?? resolveMember(childMember, document2.members)
10678
- ))
10679
- return [];
10680
- const member = substituteMember(
10681
- childMember,
10682
- instanceEnv,
10683
- document2.members,
10684
- document2.resolvedMember?.(childMember)
10685
- );
10686
- return [
10687
- {
10688
- schemaKey: entry.schemaKey,
10689
- member,
10690
- defaultSettlesConstruction: settlesConstruction(member, instanceEnv),
10691
- directScalarBody: directScalarDefaultBody(document2, member)
10692
- }
10693
- ];
10694
- });
10790
+ return storedSchemaOf(document2, classId).flatMap(
10791
+ (entry) => {
10792
+ if (entry.memberId === null) return [];
10793
+ const childMember = findMemberInDocument(document2, entry.memberId);
10794
+ if (!memberKindOwnsStoredValue(childMember.kind)) return [];
10795
+ if (instanceEnv.size === 0 && isConstantMember(document2, resolvedInDocument(document2, childMember)))
10796
+ return [];
10797
+ const member = substituteMember(
10798
+ childMember,
10799
+ instanceEnv,
10800
+ document2.members,
10801
+ document2.resolvedMember?.(childMember)
10802
+ );
10803
+ return [
10804
+ {
10805
+ schemaKey: entry.schemaKey,
10806
+ member,
10807
+ defaultSettlesConstruction: settlesConstruction(member, instanceEnv),
10808
+ directScalarBody: directScalarDefaultBody(document2, member)
10809
+ }
10810
+ ];
10811
+ }
10812
+ );
10695
10813
  }
10696
- function isImmutableConstantMember(document2, resolved) {
10697
- if (resolved.storage !== 1 /* Immutable */) return false;
10814
+ function isConstantMember(document2, resolved) {
10698
10815
  if (isStaticMember(resolved)) return false;
10816
+ const fixedness = fixednessOf(resolved, 0 /* Writable */);
10817
+ if (fixedness === 0 /* Writable */) return false;
10699
10818
  const declared = resolved.defaultValue;
10700
10819
  if (declared == null) return false;
10701
- return !declarationReadsInstance(
10702
- { document: document2, visited: /* @__PURE__ */ new Set() },
10820
+ if (fixedness === 1 /* ReadOnly */ && (isMemberListBase(resolved) || isMemberDictionaryBase(resolved)))
10821
+ return false;
10822
+ return !declarationVaries(
10823
+ {
10824
+ document: document2,
10825
+ rows: /* @__PURE__ */ new Set(),
10826
+ declarations: /* @__PURE__ */ new Set(),
10827
+ classes: /* @__PURE__ */ new Set()
10828
+ },
10703
10829
  resolved,
10704
10830
  declared,
10705
- null
10831
+ null,
10832
+ { fixedness, ownsReads: true }
10706
10833
  );
10707
10834
  }
10708
- function declarationReadsInstance(walk, member, body, rowId) {
10835
+ function fixednessOf(resolved, parent) {
10836
+ const storage = resolved.storage ?? 0 /* Inherit */;
10837
+ if (storage === 1 /* Immutable */) return 2 /* Immutable */;
10838
+ if (storage === 0 /* Inherit */ && parent === 2 /* Immutable */)
10839
+ return 2 /* Immutable */;
10840
+ return isReadOnlyMember(resolved) ? 1 /* ReadOnly */ : 0 /* Writable */;
10841
+ }
10842
+ function scopeKey(id, scope) {
10843
+ return `${id}:${scope.fixedness}:${scope.ownsReads}`;
10844
+ }
10845
+ function resolvedInDocument(document2, member) {
10846
+ return document2.resolvedMember?.(member) ?? resolveMember(member, document2.members);
10847
+ }
10848
+ function declarationVaries(walk, member, body, rowId, scope) {
10709
10849
  const { document: document2 } = walk;
10850
+ const { ownsReads } = scope;
10851
+ const immutable2 = scope.fixedness === 2 /* Immutable */;
10710
10852
  if (documentHasInitValueContent(document2, body)) {
10711
- const compiled = body.init.compiled;
10712
- if (compiled === void 0) return true;
10713
- const instanceParameters = /* @__PURE__ */ new Set();
10714
- for (const parameter3 of compiled.parameters) {
10715
- if (parameter3.id !== "__root__") instanceParameters.add(parameter3.id);
10716
- }
10717
- return irReadsInstance(
10718
- compiled.instructions,
10719
- instanceParameters,
10720
- /* @__PURE__ */ new Set()
10721
- );
10853
+ if (!immutable2) return true;
10854
+ if (ownsReads) {
10855
+ const compiled = body.init.compiled;
10856
+ if (compiled === void 0) return true;
10857
+ if (initializerReadsInstance(compiled)) return true;
10858
+ }
10859
+ return typeHoldsWritable(walk, member, 2 /* Immutable */);
10722
10860
  }
10723
10861
  if (!isLiteralValueContent(body)) return true;
10724
- if (irReadsInstance(body.constructorArgs, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set())) return true;
10862
+ if (!immutable2 && body.instanceConstructorId !== void 0) return true;
10863
+ if (!immutable2 && body.constructorArgs != null) return true;
10864
+ if (ownsReads && irReadsInstance(body.constructorArgs, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set()))
10865
+ return true;
10725
10866
  const value = body.value;
10726
- const ownedEntry = (entryMember) => (valueId) => typeof valueId !== "string" || rowReadsInstance(walk, entryMember, valueId);
10727
10867
  if (isMemberClassBase(member)) {
10728
10868
  if (value === null) return false;
10729
10869
  if (!isStringRecord(value)) return true;
10730
10870
  const classId = typeof body.classId === "string" ? body.classId : member.classId;
10731
- const entries = getSchemaEntryMap(document2, classId);
10732
- for (const [schemaKey, valueId] of Object.entries(value)) {
10733
- const memberId = entries.get(schemaKey)?.memberId;
10734
- if (memberId == null) return true;
10735
- const child = findMemberInDocument(document2, memberId);
10736
- if (ownedEntry(child)(valueId)) return true;
10871
+ let owned = 0;
10872
+ for (const entry of storedSchemaOf(document2, classId)) {
10873
+ if (entry.memberId === null) continue;
10874
+ const child = resolvedInDocument(
10875
+ document2,
10876
+ findMemberInDocument(document2, entry.memberId)
10877
+ );
10878
+ const childId = value[entry.schemaKey];
10879
+ if (childId !== void 0) owned++;
10880
+ else if (!memberKindOwnsStoredValue(child.kind) || isStaticMember(child))
10881
+ continue;
10882
+ const fixedness = fixednessOf(child, scope.fixedness);
10883
+ if (fixedness === 0 /* Writable */) return true;
10884
+ if (childId !== void 0) {
10885
+ if (rowVaries(walk, child, childId, { fixedness, ownsReads }))
10886
+ return true;
10887
+ continue;
10888
+ }
10889
+ const declared = child.defaultValue;
10890
+ if (declared == null) continue;
10891
+ const childScope = { fixedness, ownsReads: false };
10892
+ const key = scopeKey(entry.memberId, childScope);
10893
+ if (walk.declarations.has(key)) continue;
10894
+ walk.declarations.add(key);
10895
+ if (declarationVaries(walk, child, declared, null, childScope))
10896
+ return true;
10737
10897
  }
10738
- return false;
10898
+ return owned !== Object.keys(value).length;
10739
10899
  }
10740
10900
  if (isMemberListBase(member)) {
10741
- const entryMember = findMemberInDocument(document2, member.entryMemberId);
10742
10901
  const entryIds = listKindOf(member) !== 1 /* Unordered */ ? value : rowId === null ? [] : document2.unorderedListEntryIds?.(rowId) ?? (walk.membership ??= buildUnorderedListMembershipIndex(
10743
10902
  document2.values
10744
10903
  )).get(rowId) ?? [];
10745
10904
  if (entryIds === null) return false;
10746
- return !Array.isArray(entryIds) || entryIds.some(ownedEntry(entryMember));
10905
+ if (!Array.isArray(entryIds)) return true;
10906
+ return entriesVary(walk, member.entryMemberId, entryIds, scope);
10747
10907
  }
10748
10908
  if (isMemberDictionaryBase(member)) {
10749
10909
  if (value === null) return false;
10750
10910
  if (!isStringRecord(value)) return true;
10751
- const entryMember = findMemberInDocument(document2, member.entryMemberId);
10752
- return Object.values(value).some(ownedEntry(entryMember));
10911
+ return entriesVary(walk, member.entryMemberId, Object.values(value), scope);
10753
10912
  }
10754
10913
  if (member.kind === 21 /* Generic */) return true;
10755
- return irReadsInstance(value, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set());
10914
+ return ownsReads && irReadsInstance(value, /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set());
10915
+ }
10916
+ function entriesVary(walk, entryMemberId, entryIds, scope) {
10917
+ if (entryIds.length === 0) return false;
10918
+ const entryMember = resolvedInDocument(
10919
+ walk.document,
10920
+ findMemberInDocument(walk.document, entryMemberId)
10921
+ );
10922
+ const fixedness = fixednessOf(entryMember, scope.fixedness);
10923
+ if (fixedness === 0 /* Writable */) return true;
10924
+ const entryScope = { fixedness, ownsReads: scope.ownsReads };
10925
+ return entryIds.some(
10926
+ (entryId) => typeof entryId !== "string" || rowVaries(walk, entryMember, entryId, entryScope)
10927
+ );
10756
10928
  }
10757
- function rowReadsInstance(walk, member, valueId) {
10758
- if (walk.visited.has(valueId)) return false;
10759
- walk.visited.add(valueId);
10929
+ function rowVaries(walk, member, valueId, scope) {
10930
+ const key = scopeKey(valueId, scope);
10931
+ if (walk.rows.has(key)) return false;
10932
+ walk.rows.add(key);
10760
10933
  const { document: document2 } = walk;
10761
10934
  const row = document2.valueById?.(valueId) ?? (walk.rowById ??= new Map(
10762
10935
  document2.values.map((value) => [value.id, value])
10763
10936
  )).get(valueId);
10764
10937
  if (row === void 0 || row === null) return true;
10765
- const resolved = document2.resolvedMember?.(member) ?? resolveMember(member, document2.members);
10766
- return declarationReadsInstance(walk, resolved, row, row.id);
10938
+ return declarationVaries(walk, member, row, row.id, scope);
10939
+ }
10940
+ function typeHoldsWritable(walk, member, fixedness) {
10941
+ if (isMemberClassBase(member)) {
10942
+ const { classes } = walk.document;
10943
+ if (!classIndexFor(classes).has(member.classId)) return true;
10944
+ if (classHoldsWritable(walk, member.classId, fixedness)) return true;
10945
+ for (const classId of descendantClassIds(member.classId, classes)) {
10946
+ if (classHoldsWritable(walk, classId, fixedness)) return true;
10947
+ }
10948
+ return false;
10949
+ }
10950
+ if (isMemberListBase(member) || isMemberDictionaryBase(member)) {
10951
+ const entryMember = resolvedInDocument(
10952
+ walk.document,
10953
+ findMemberInDocument(walk.document, member.entryMemberId)
10954
+ );
10955
+ const entryFixedness = fixednessOf(entryMember, fixedness);
10956
+ return entryFixedness === 0 /* Writable */ || typeHoldsWritable(walk, entryMember, entryFixedness);
10957
+ }
10958
+ return member.kind === 21 /* Generic */;
10959
+ }
10960
+ function classHoldsWritable(walk, classId, fixedness) {
10961
+ const key = `${classId}:${fixedness}`;
10962
+ if (walk.classes.has(key)) return false;
10963
+ walk.classes.add(key);
10964
+ const { document: document2 } = walk;
10965
+ for (const entry of storedSchemaOf(document2, classId)) {
10966
+ if (entry.memberId === null) continue;
10967
+ const child = resolvedInDocument(
10968
+ document2,
10969
+ findMemberInDocument(document2, entry.memberId)
10970
+ );
10971
+ if (!memberKindOwnsStoredValue(child.kind) || isStaticMember(child))
10972
+ continue;
10973
+ const childFixedness = fixednessOf(child, fixedness);
10974
+ if (childFixedness === 0 /* Writable */) return true;
10975
+ if (typeHoldsWritable(walk, child, childFixedness)) return true;
10976
+ }
10977
+ return false;
10978
+ }
10979
+ function storedSchemaOf(document2, classId) {
10980
+ return document2.storedInstanceSchema?.(classId) ?? resolvedClassSchema(classId, document2.classes, document2.members).surface;
10981
+ }
10982
+ function initializerReadsInstance(compiled) {
10983
+ const instanceParameters = /* @__PURE__ */ new Set();
10984
+ for (const parameter3 of compiled.parameters) {
10985
+ if (parameter3.id !== "__root__") instanceParameters.add(parameter3.id);
10986
+ }
10987
+ return irReadsInstance(compiled.instructions, instanceParameters, /* @__PURE__ */ new Set());
10767
10988
  }
10768
10989
  function irReadsInstance(value, instanceParameters, visited) {
10769
10990
  if (typeof value !== "object" || value === null) return false;
@@ -15468,7 +15689,9 @@ function readClassMember(args) {
15468
15689
  const expanded = args.expandedRecord();
15469
15690
  if (expanded !== null && Object.prototype.hasOwnProperty.call(expanded, schemaKey))
15470
15691
  return { kind: "value", value: Reflect.get(expanded, schemaKey) };
15471
- if (args.mode !== "resolved" && declaration !== void 0)
15692
+ if (args.mode === "resolved")
15693
+ return declaration !== void 0 && args.isConstant() ? { kind: "declaration", content: declaration } : { kind: "missing" };
15694
+ if (declaration !== void 0)
15472
15695
  return { kind: "declaration", content: declaration };
15473
15696
  if (args.mode === "runtime" && !isRequiredMember(member))
15474
15697
  return { kind: "null" };
@@ -16974,6 +17197,7 @@ function withEvaluationRuntime(ctx, writes) {
16974
17197
  constructionTimestamp: Date.now(),
16975
17198
  ownedValueAttachments: /* @__PURE__ */ new Map(),
16976
17199
  constructionStack: [],
17200
+ openConstructions: /* @__PURE__ */ new Map(),
16977
17201
  loopIterations: 0,
16978
17202
  budgetedConstructedRowIds: /* @__PURE__ */ new Set(),
16979
17203
  budgetedProducedEntriesByRowId: /* @__PURE__ */ new Map(),
@@ -18109,14 +18333,16 @@ function evalInstructions(instructions, scope, ctx, options) {
18109
18333
  };
18110
18334
  }
18111
18335
  const assignedReferenceValueId = targetTypeInfo.type === 7 /* Class */ || targetTypeInfo.type === 6 /* List */ || targetTypeInfo.type === 5 /* Dictionary */ ? findKnownRowIdByValueReference(value, ctx) : null;
18112
- applyOverlayAssignment(
18113
- ins.target.pointer,
18114
- targetTypeInfo,
18115
- value,
18116
- scope,
18117
- ctx,
18118
- destination
18119
- );
18336
+ if (!bindOmittedConstantSlot(destination, member, value, ctx)) {
18337
+ applyOverlayAssignment(
18338
+ ins.target.pointer,
18339
+ targetTypeInfo,
18340
+ value,
18341
+ scope,
18342
+ ctx,
18343
+ destination
18344
+ );
18345
+ }
18120
18346
  const unorderedReplacement = assignedReferenceValueId === null && member !== null && isMemberListBase(member) && listKindOf(member) === 1 /* Unordered */ && Array.isArray(value) ? unorderedReplacementProjection(
18121
18347
  ins.target.pointer,
18122
18348
  destination,
@@ -18971,6 +19197,36 @@ function applyOverlayStaticAssignment(memberId, value, ctx) {
18971
19197
  bindings.set(member.id, row.id);
18972
19198
  invalidateEvaluatorIndexes(ctx);
18973
19199
  }
19200
+ function bindOmittedConstantSlot(destination, member, value, ctx) {
19201
+ if (destination === void 0 || member === null) return false;
19202
+ const { receiver } = destination;
19203
+ if (typeof receiver !== "object" || receiver === null) return false;
19204
+ const construction = ctx.__executionState?.openConstructions.get(receiver);
19205
+ if (construction === void 0) return false;
19206
+ const key = String(destination.key);
19207
+ if (Object.prototype.hasOwnProperty.call(receiver, key)) return false;
19208
+ if (isMemberClassBase(member) || isMemberListBase(member) || isMemberDictionaryBase(member))
19209
+ return false;
19210
+ const resolved = resolveMember(member, ctx.vm.members);
19211
+ if (!isConstantMember(constructorDefaultValueDocument(ctx, member), resolved))
19212
+ return false;
19213
+ const { createdValues } = construction;
19214
+ const staged = createdValues.length;
19215
+ const row = materializeConstructorArgumentValue({
19216
+ member: resolved,
19217
+ value,
19218
+ // A constant has no instance environment.
19219
+ genericEnv: /* @__PURE__ */ new Map(),
19220
+ ctx,
19221
+ createdValues,
19222
+ createdById: /* @__PURE__ */ new Map(),
19223
+ storageKeyDeclarations: construction.storageKeyDeclarations
19224
+ });
19225
+ stageConstructedRows(createdValues.slice(staged), ctx);
19226
+ Reflect.set(receiver, key, row.id);
19227
+ invalidateEvaluatorIndexes(ctx, receiver);
19228
+ return true;
19229
+ }
18974
19230
  function touchUnknown(_ins) {
18975
19231
  void _ins;
18976
19232
  }
@@ -21358,7 +21614,7 @@ function readDeclarationDefault(member, ctx) {
21358
21614
  };
21359
21615
  }
21360
21616
  const document2 = constructorDefaultValueDocument(ctx, member);
21361
- const constant = shared !== void 0 && known !== false && (known !== void 0 || isImmutableConstantMember(document2, member));
21617
+ const constant = shared !== void 0 && known !== false && (known !== void 0 || isConstantMember(document2, member));
21362
21618
  if (shared !== void 0 && !constant) shared.set(member.id, false);
21363
21619
  const created = [];
21364
21620
  const closeFrame = pushConstructionFrame(ctx, `${member.name} declaration`);
@@ -24713,6 +24969,11 @@ function evaluateInitializerInContext(init, member, ctx, createdValues, argument
24713
24969
  sessionValueExport: "defer"
24714
24970
  }
24715
24971
  );
24972
+ } catch (error) {
24973
+ const ownerId = compileMemberId ?? Reflect.get(member, "id");
24974
+ if (error instanceof NSGetterRuntimeError && sourceValueId === null && typeof ownerId === "string")
24975
+ error.sourceOwnerId ??= ownerId;
24976
+ throw error;
24716
24977
  } finally {
24717
24978
  closeFrame();
24718
24979
  }
@@ -25865,39 +26126,50 @@ function constructDeclaredClassValueWithinFrame(descriptor, record4, info, scope
25865
26126
  stageConstructedRows(createdValues, ctx);
25866
26127
  bindConstructedDelegateTargets(createdValues, ctx);
25867
26128
  if (record4 !== null) {
25868
- runDeclaredConstructorChain({
25869
- record: record4,
25870
- argumentValues,
25871
- preparedArgumentScopes,
25872
- thisValue: root.value,
25873
- ctx,
25874
- visitedConstructorIds: /* @__PURE__ */ new Set(),
25875
- applyBaseInitializerBlock: (chainRecord, chainArguments, chainThisValue) => {
25876
- const supplied2 = evaluateBaseInitializerFields({
25877
- record: chainRecord,
25878
- argumentValues: chainArguments,
25879
- thisValue: chainThisValue,
25880
- constructedClassId: classId,
25881
- instanceEnv: descriptor.instanceEnv,
25882
- ctx
25883
- });
25884
- if (supplied2.length === 0) return;
25885
- applyConstructorFields({
25886
- supplied: supplied2,
25887
- root,
25888
- rootRecord,
25889
- schemaClass: schemaClass2,
25890
- instanceEnv: descriptor.instanceEnv,
25891
- createdValues,
25892
- createdById: new Map(createdValues.map((row) => [row.id, row])),
25893
- storageKeyDeclarations,
25894
- // §1.5 base blocks are assignments, not omissions: an explicit null
25895
- // clears the slot exactly as a call-site block entry does.
25896
- nullMeansOmit: false,
25897
- ctx
25898
- });
25899
- }
26129
+ const openConstructions = ctx.__executionState?.openConstructions;
26130
+ openConstructions?.set(rootRecord, {
26131
+ createdValues,
26132
+ storageKeyDeclarations
25900
26133
  });
26134
+ try {
26135
+ runDeclaredConstructorChain({
26136
+ record: record4,
26137
+ argumentValues,
26138
+ preparedArgumentScopes,
26139
+ thisValue: root.value,
26140
+ ctx,
26141
+ visitedConstructorIds: /* @__PURE__ */ new Set(),
26142
+ applyBaseInitializerBlock: (chainRecord, chainArguments, chainThisValue) => {
26143
+ const supplied2 = evaluateBaseInitializerFields({
26144
+ record: chainRecord,
26145
+ argumentValues: chainArguments,
26146
+ thisValue: chainThisValue,
26147
+ constructedClassId: classId,
26148
+ instanceEnv: descriptor.instanceEnv,
26149
+ ctx
26150
+ });
26151
+ if (supplied2.length === 0) return;
26152
+ const staged = createdValues.length;
26153
+ applyConstructorFields({
26154
+ supplied: supplied2,
26155
+ root,
26156
+ rootRecord,
26157
+ schemaClass: schemaClass2,
26158
+ instanceEnv: descriptor.instanceEnv,
26159
+ createdValues,
26160
+ createdById: new Map(createdValues.map((row) => [row.id, row])),
26161
+ storageKeyDeclarations,
26162
+ // §1.5 base blocks are assignments, not omissions: an explicit null
26163
+ // clears the slot exactly as a call-site block entry does.
26164
+ nullMeansOmit: false,
26165
+ ctx
26166
+ });
26167
+ stageConstructedRows(createdValues.slice(staged), ctx);
26168
+ }
26169
+ });
26170
+ } finally {
26171
+ openConstructions?.delete(rootRecord);
26172
+ }
25901
26173
  }
25902
26174
  const supplied = evaluateConstructorFields(descriptor, scope, ctx);
25903
26175
  try {
@@ -29272,11 +29544,8 @@ var Parser = class _Parser {
29272
29544
  * always opens with a type expression, which can be:
29273
29545
  * - A primitive keyword: int / float / bool / string
29274
29546
  * - `Dictionary` keyword followed by `<`
29275
- * - An identifier (Class or Enum) with `[]` suffix or
29276
- * followed by another identifier (the var name).
29277
- *
29278
- * We don't fully parse the type here — we just decide whether to commit
29279
- * to the varDecl path or fall through to an expression statement.
29547
+ * - Any other type the type grammar parses (`Item[]`, `Box<int>?`,
29548
+ * `NeoDelegate<int, int>`) followed by the var name and `=`.
29280
29549
  */
29281
29550
  looksLikeVarDecl() {
29282
29551
  const t = this.peek();
@@ -29293,25 +29562,53 @@ var Parser = class _Parser {
29293
29562
  return true;
29294
29563
  }
29295
29564
  if (!isIdentifier(t)) return false;
29296
- let j = this.i + 1;
29297
- const tk = (k) => this.tokens[k];
29298
- while (tk(j)?.kind === "punctuation" && tk(j)?.text === "[" && tk(j + 1)?.kind === "punctuation" && tk(j + 1)?.text === "]") {
29299
- j += 2;
29300
- }
29301
- if (tk(j)?.kind === "operator" && tk(j)?.text === "?") {
29302
- j += 1;
29303
- }
29304
- const name = tk(j);
29305
- if (name !== void 0 && isIdentifier(name) && tk(j + 1)?.kind === "operator" && tk(j + 1)?.text === "=") {
29306
- return true;
29565
+ const end = this.typeEnd();
29566
+ const name = this.tokens[end];
29567
+ const equals = this.tokens[end + 1];
29568
+ return end >= 0 && name !== void 0 && isIdentifier(name) && equals?.kind === "operator" && equals.text === "=";
29569
+ }
29570
+ /**
29571
+ * Token index just past the type that starts at the cursor, or -1 when the
29572
+ * type grammar rejects it. The cursor does not move. Editor recovery shares
29573
+ * this with declaration lookahead so both agree on every type form.
29574
+ */
29575
+ typeEnd(options = {}) {
29576
+ const start = this.i;
29577
+ this.probingType = true;
29578
+ try {
29579
+ return this.parseTypeOrFail(options) ? this.i : -1;
29580
+ } catch {
29581
+ return -1;
29582
+ } finally {
29583
+ this.probingType = false;
29584
+ this.i = start;
29307
29585
  }
29308
- return false;
29586
+ }
29587
+ /**
29588
+ * True while `typeEnd` probes. Lookahead runs at every identifier on editor
29589
+ * paths, so a rejected type returns null instead of constructing an error.
29590
+ */
29591
+ probingType = false;
29592
+ /** A type-grammar failure: null while probing, otherwise a CompileError. */
29593
+ typeFailure(message, token) {
29594
+ if (this.probingType) return null;
29595
+ throw new CompileError(message, at(token));
29596
+ }
29597
+ /** `expect` inside the type grammar: false while probing a mismatch. */
29598
+ expectTypeToken(kind, text) {
29599
+ if (this.probingType && !tokenMatches(this.peek(), kind, text))
29600
+ return false;
29601
+ this.expect(kind, text);
29602
+ return true;
29309
29603
  }
29310
29604
  // ------------------------------------------------------------------
29311
29605
  // Types
29312
29606
  // ------------------------------------------------------------------
29313
29607
  /** Parses a type annotation (used in varDecls and Dictionary generics). */
29314
29608
  parseType(options = {}) {
29609
+ return this.parseTypeOrFail(options);
29610
+ }
29611
+ parseTypeOrFail(options) {
29315
29612
  const startPos = at(this.peek());
29316
29613
  let inner;
29317
29614
  const t = this.peek();
@@ -29325,17 +29622,18 @@ var Parser = class _Parser {
29325
29622
  };
29326
29623
  } else if (t.kind === "type" && (t.text === "Dictionary" || t.text === "List" || t.text === "Set")) {
29327
29624
  this.next();
29328
- this.expect("operator", "<");
29625
+ if (!this.expectTypeToken("operator", "<")) return null;
29329
29626
  if (t.text === "Dictionary") {
29330
- const key = this.parseType();
29627
+ const key = this.parseTypeOrFail({});
29628
+ if (!key) return null;
29331
29629
  if (this.peek().text === ">")
29332
- throw new CompileError(
29630
+ return this.typeFailure(
29333
29631
  "Dictionary requires a key type and a value type, for example Dictionary<string, int>.",
29334
- at(this.peek())
29632
+ this.peek()
29335
29633
  );
29336
- this.expect("punctuation", ",");
29337
- const value = this.parseType();
29338
- this.expect("operator", ">");
29634
+ if (!this.expectTypeToken("punctuation", ",")) return null;
29635
+ const value = this.parseTypeOrFail({});
29636
+ if (!value || !this.expectTypeToken("operator", ">")) return null;
29339
29637
  inner = {
29340
29638
  kind: "dict",
29341
29639
  key,
@@ -29344,8 +29642,8 @@ var Parser = class _Parser {
29344
29642
  pos: startPos
29345
29643
  };
29346
29644
  } else {
29347
- const element = this.parseType();
29348
- this.expect("operator", ">");
29645
+ const element = this.parseTypeOrFail({});
29646
+ if (!element || !this.expectTypeToken("operator", ">")) return null;
29349
29647
  inner = {
29350
29648
  kind: t.text === "List" ? "list" : "set",
29351
29649
  element,
@@ -29357,10 +29655,12 @@ var Parser = class _Parser {
29357
29655
  this.next();
29358
29656
  const typeArguments = [];
29359
29657
  if (this.eat("operator", "<")) {
29360
- typeArguments.push(this.parseType());
29361
- while (this.eat("punctuation", ","))
29362
- typeArguments.push(this.parseType());
29363
- this.expect("operator", ">");
29658
+ do {
29659
+ const argument2 = typeArguments.length === 0 && t.text === "NeoDelegate" ? this.parseDelegateReturnType() : this.parseTypeOrFail({});
29660
+ if (!argument2) return null;
29661
+ typeArguments.push(argument2);
29662
+ } while (this.eat("punctuation", ","));
29663
+ if (!this.expectTypeToken("operator", ">")) return null;
29364
29664
  }
29365
29665
  inner = {
29366
29666
  kind: "named",
@@ -29370,7 +29670,7 @@ var Parser = class _Parser {
29370
29670
  pos: startPos
29371
29671
  };
29372
29672
  } else {
29373
- throw new CompileError(`Expected a type, got ${describeToken(t)}`, at(t));
29673
+ return this.typeFailure(`Expected a type, got ${describeToken(t)}`, t);
29374
29674
  }
29375
29675
  while (this.peek().kind === "punctuation" && this.peek().text === "[" && this.peek(1).kind === "punctuation" && this.peek(1).text === "]") {
29376
29676
  const arrPos = at(this.peek());
@@ -29389,6 +29689,14 @@ var Parser = class _Parser {
29389
29689
  }
29390
29690
  return inner;
29391
29691
  }
29692
+ /** `NeoDelegate<void, …>`: the return slot is the one type that may be `void`. */
29693
+ parseDelegateReturnType() {
29694
+ const t = this.peek();
29695
+ if (t.kind !== "keyword" || t.text !== "void")
29696
+ return this.parseTypeOrFail({});
29697
+ this.next();
29698
+ return { kind: "primitive", name: "void", required: true, pos: at(t) };
29699
+ }
29392
29700
  /**
29393
29701
  * `is T ? a : b` is ambiguous at the token level because `?` is also the
29394
29702
  * nullable type suffix. A colon at the same delimiter depth makes it the
@@ -29743,7 +30051,7 @@ var Parser = class _Parser {
29743
30051
  }
29744
30052
  while (true) {
29745
30053
  let name = null;
29746
- if ((isIdentifier(this.peek()) || this.peek().kind === "keyword" && (this.peek().text === "default" || isValidNeoProjectIdentifier(this.peek().text))) && this.peek(1).kind === "punctuation" && this.peek(1).text === ":") {
30054
+ if (isCallArgumentLabelToken(this.peek()) && this.peek(1).kind === "punctuation" && this.peek(1).text === ":") {
29747
30055
  name = this.next().text;
29748
30056
  this.next();
29749
30057
  }
@@ -30226,6 +30534,9 @@ function at(token) {
30226
30534
  function tokenMatches(token, kind, text) {
30227
30535
  return (kind === "identifier" ? isIdentifier(token) : token.kind === kind) && (text === void 0 || token.text === text);
30228
30536
  }
30537
+ function isCallArgumentLabelToken(token) {
30538
+ return isIdentifier(token) || token.kind === "keyword" && (token.text === "default" || isValidNeoProjectIdentifier(token.text));
30539
+ }
30229
30540
  function isIdentifier(token) {
30230
30541
  return token.kind === "identifier" || token.kind === "type" && token.text !== "int" && token.text !== "float" && token.text !== "decimal" && token.text !== "bool" && token.text !== "string" && token.text !== "Dictionary" && token.text !== "List" && token.text !== "Set";
30231
30542
  }
@@ -32829,6 +33140,9 @@ function evaluateMemberInitializer(args) {
32829
33140
  } catch (error) {
32830
33141
  if (error instanceof NSGetterRuntimeError) {
32831
33142
  error.initializerValueId ??= args.sourceValueId ?? void 0;
33143
+ const memberId = Reflect.get(args.member, "id");
33144
+ if (args.sourceValueId == null && typeof memberId === "string")
33145
+ error.sourceOwnerId ??= memberId;
32832
33146
  }
32833
33147
  throw error;
32834
33148
  }
@@ -33093,6 +33407,9 @@ function buildNeoScriptEditorIndex(lexed, kind) {
33093
33407
  const references = [];
33094
33408
  const calls = [];
33095
33409
  const switches = [];
33410
+ const lambdaBodies = [];
33411
+ const contextualKeywordRanges = [];
33412
+ const objectInitializers = [];
33096
33413
  for (const executable of executableRegions) {
33097
33414
  const executablePairs = pairBrackets(executable);
33098
33415
  const regionSwitches = indexSwitchStatements(
@@ -33102,7 +33419,13 @@ function buildNeoScriptEditorIndex(lexed, kind) {
33102
33419
  diagnostics
33103
33420
  );
33104
33421
  const regionLocals = applySwitchSectionScopes(
33105
- indexLocals(executable, executablePairs, lexed, diagnostics),
33422
+ indexLocals(
33423
+ executable,
33424
+ executablePairs,
33425
+ lexed,
33426
+ diagnostics,
33427
+ lambdaBodies
33428
+ ),
33106
33429
  regionSwitches,
33107
33430
  lexed
33108
33431
  );
@@ -33113,24 +33436,36 @@ function buildNeoScriptEditorIndex(lexed, kind) {
33113
33436
  )
33114
33437
  );
33115
33438
  const contextualKeywords = new Set(
33116
- [
33117
- ...regionLocals.flatMap(
33118
- (local) => local.contextualKeywordRange ? [local.contextualKeywordRange] : []
33119
- ),
33120
- ...regionCalls.flatMap(
33121
- (call) => call.contextualKeywordRange ? [call.contextualKeywordRange] : []
33122
- )
33123
- ].map((range2) => `${range2.start.line}:${range2.start.character}`)
33439
+ regionLocals.flatMap(
33440
+ (local) => local.contextualKeywordRange ? [local.contextualKeywordRange] : []
33441
+ ).map((range2) => `${range2.start.line}:${range2.start.character}`)
33124
33442
  );
33125
33443
  locals.push(...regionLocals);
33126
33444
  references.push(
33127
- ...indexReferences(executable, declarations, contextualKeywords)
33445
+ ...indexReferences(
33446
+ executable,
33447
+ executablePairs,
33448
+ declarations,
33449
+ contextualKeywords,
33450
+ contextualKeywordRanges,
33451
+ objectInitializers
33452
+ )
33128
33453
  );
33129
33454
  calls.push(...regionCalls);
33130
33455
  switches.push(...regionSwitches);
33131
33456
  validateTerminatedStatements(executable, diagnostics);
33132
33457
  }
33133
- return { units, locals, references, calls, switches, diagnostics };
33458
+ return {
33459
+ units,
33460
+ locals,
33461
+ references,
33462
+ calls,
33463
+ switches,
33464
+ lambdaBodies,
33465
+ contextualKeywordRanges,
33466
+ objectInitializers,
33467
+ diagnostics
33468
+ };
33134
33469
  }
33135
33470
  function indexUnits(tokens, pairs, kind, lexed) {
33136
33471
  if (kind !== "property") {
@@ -33547,8 +33882,9 @@ function duplicateUnitDiagnostic(label, units, diagnostics) {
33547
33882
  ]
33548
33883
  });
33549
33884
  }
33550
- function indexLocals(tokens, pairs, lexed, diagnostics) {
33885
+ function indexLocals(tokens, pairs, lexed, diagnostics, lambdaBodies) {
33551
33886
  const locals = [];
33887
+ const braceScope = braceScopeIndex(tokens, lexed.end);
33552
33888
  for (let index = 0; index < tokens.length; index++) {
33553
33889
  const caught = tryParseCatchParameter(tokens, index, pairs, lexed);
33554
33890
  if (caught) {
@@ -33556,7 +33892,14 @@ function indexLocals(tokens, pairs, lexed, diagnostics) {
33556
33892
  index = caught.resumeTokenIndex;
33557
33893
  continue;
33558
33894
  }
33559
- const loop = tryParseLoopLocal(tokens, index, pairs, lexed, diagnostics);
33895
+ const loop = tryParseLoopLocal(
33896
+ tokens,
33897
+ index,
33898
+ pairs,
33899
+ lexed,
33900
+ diagnostics,
33901
+ braceScope
33902
+ );
33560
33903
  if (loop) {
33561
33904
  locals.push(...loop.locals);
33562
33905
  index = loop.resumeTokenIndex;
@@ -33565,10 +33908,16 @@ function indexLocals(tokens, pairs, lexed, diagnostics) {
33565
33908
  const lambda = tryParseLambdaParameters(tokens, index, pairs, lexed);
33566
33909
  if (lambda) {
33567
33910
  locals.push(...lambda.locals);
33911
+ lambdaBodies.push(lambda.body);
33568
33912
  index = lambda.endTokenIndex;
33569
33913
  continue;
33570
33914
  }
33571
- const declaration = tryParseVariableDeclaration(tokens, index, lexed);
33915
+ const declaration = tryParseVariableDeclaration(
33916
+ tokens,
33917
+ index,
33918
+ lexed,
33919
+ braceScope
33920
+ );
33572
33921
  if (!declaration) continue;
33573
33922
  locals.push(declaration.local);
33574
33923
  if (declaration.missingInitializer) {
@@ -33584,36 +33933,14 @@ function indexLocals(tokens, pairs, lexed, diagnostics) {
33584
33933
  }
33585
33934
  return locals;
33586
33935
  }
33587
- function tryParseVariableDeclaration(tokens, start, lexed) {
33936
+ function tryParseVariableDeclaration(tokens, start, lexed, braceScope) {
33588
33937
  const first = tokens[start];
33589
33938
  if (!first || first.kind !== "type" && first.kind !== "identifier")
33590
33939
  return null;
33591
33940
  const inferred = first.kind === "identifier" && first.text === NEOSCRIPT_INFERRED_LOCAL_KEYWORD;
33592
- let cursor = start + 1;
33593
- if (!inferred && (first.text === "Dictionary" || first.text === "Set")) {
33594
- const open = tokens[cursor];
33595
- if (!open || open.kind !== "operator" || open.text !== "<") return null;
33596
- let angleDepth = 0;
33597
- while (cursor < tokens.length) {
33598
- const token = tokens[cursor];
33599
- if (!token) return null;
33600
- if (token.kind === "operator" && token.text === "<") angleDepth++;
33601
- if (token.kind === "operator" && token.text === ">") {
33602
- angleDepth--;
33603
- if (angleDepth === 0) {
33604
- cursor++;
33605
- break;
33606
- }
33607
- }
33608
- cursor++;
33609
- }
33610
- }
33611
- while (!inferred && tokens[cursor]?.kind === "punctuation" && tokens[cursor]?.text === "[" && tokens[cursor + 1]?.kind === "punctuation" && tokens[cursor + 1]?.text === "]") {
33612
- cursor += 2;
33613
- }
33614
- if (!inferred && tokens[cursor]?.kind === "operator" && tokens[cursor]?.text === "?") {
33615
- cursor++;
33616
- }
33941
+ if (!inferred && !mayStartTypedLocal(tokens, start)) return null;
33942
+ const cursor = inferred ? start + 1 : new Parser(tokens, start).typeEnd();
33943
+ if (cursor < 0) return null;
33617
33944
  const name = tokens[cursor];
33618
33945
  const equals = tokens[cursor + 1];
33619
33946
  if (!name || name.kind !== "identifier") return null;
@@ -33625,7 +33952,7 @@ function tryParseVariableDeclaration(tokens, start, lexed) {
33625
33952
  const statementEnd = statementEndTokenIndex(tokens, cursor + 2);
33626
33953
  const initializerTokens = hasEquals ? tokens.slice(cursor + 2, statementEnd) : [];
33627
33954
  const terminator = tokens[statementEnd];
33628
- const scope = containingBraceRange(tokens, start, lexed.end);
33955
+ const scope = braceScope(start);
33629
33956
  return {
33630
33957
  local: {
33631
33958
  name: name.text,
@@ -33643,6 +33970,24 @@ function tryParseVariableDeclaration(tokens, start, lexed) {
33643
33970
  missingInitializer: inferred && (!hasEquals || initializerTokens.length === 0)
33644
33971
  };
33645
33972
  }
33973
+ var STATEMENT_BOUNDARY_TOKENS = /* @__PURE__ */ new Set([
33974
+ ";",
33975
+ "{",
33976
+ "}",
33977
+ ")",
33978
+ ":"
33979
+ ]);
33980
+ function mayStartTypedLocal(tokens, start) {
33981
+ const previous = tokens[start - 1];
33982
+ if (previous && !STATEMENT_BOUNDARY_TOKENS.has(previous.text) && previous.text !== "else" && !(previous.text === "(" && tokens[start - 2]?.text === "for")) {
33983
+ return false;
33984
+ }
33985
+ const next = tokens[start + 1];
33986
+ if (!next) return false;
33987
+ if (next.kind === "identifier") return true;
33988
+ if (next.kind === "operator") return next.text === "<" || next.text === "?";
33989
+ return next.kind === "punctuation" && next.text === "[";
33990
+ }
33646
33991
  function statementEndTokenIndex(tokens, start) {
33647
33992
  let depth = 0;
33648
33993
  for (let cursor = start; cursor < tokens.length; cursor++) {
@@ -33669,6 +34014,7 @@ function tryParseLambdaParameters(tokens, start, pairs, lexed) {
33669
34014
  if (!arrow2 || arrow2.kind !== "operator" || arrow2.text !== "=>") {
33670
34015
  return null;
33671
34016
  }
34017
+ const body2 = lambdaBodySpan(tokens, start + 1, pairs, lexed);
33672
34018
  return {
33673
34019
  locals: [
33674
34020
  {
@@ -33677,17 +34023,13 @@ function tryParseLambdaParameters(tokens, start, pairs, lexed) {
33677
34023
  typeTokens: [],
33678
34024
  inferred: false,
33679
34025
  declarationRange: open.range,
33680
- scopeStart: arrow2.end,
33681
- scopeEnd: lambdaExpressionScopeEnd(
33682
- tokens,
33683
- start + 2,
33684
- pairs,
33685
- lexed.end
33686
- ),
34026
+ scopeStart: body2.start,
34027
+ scopeEnd: body2.end,
33687
34028
  lambdaParameter: true,
33688
34029
  lambdaParameterIndex: 0
33689
34030
  }
33690
34031
  ],
34032
+ body: body2,
33691
34033
  endTokenIndex: start + 1
33692
34034
  };
33693
34035
  }
@@ -33695,12 +34037,8 @@ function tryParseLambdaParameters(tokens, start, pairs, lexed) {
33695
34037
  const closeIndex = pairs.get(start);
33696
34038
  if (closeIndex === void 0) return null;
33697
34039
  const arrow = tokens[closeIndex + 1];
33698
- const bodyOpen = tokens[closeIndex + 2];
33699
34040
  if (!arrow || arrow.kind !== "operator" || arrow.text !== "=>") return null;
33700
- const hasBlockBody = bodyOpen?.kind === "punctuation" && bodyOpen.text === "{";
33701
- const bodyCloseIndex = hasBlockBody ? pairs.get(closeIndex + 2) : void 0;
33702
- const bodyClose = bodyCloseIndex === void 0 ? void 0 : tokens[bodyCloseIndex];
33703
- const scopeEnd = hasBlockBody ? bodyClose?.start ?? lexed.end : lambdaExpressionScopeEnd(tokens, closeIndex + 2, pairs, lexed.end);
34041
+ const body = lambdaBodySpan(tokens, closeIndex + 1, pairs, lexed);
33704
34042
  const locals = [];
33705
34043
  let segmentStart = start + 1;
33706
34044
  for (let cursor = start + 1; cursor <= closeIndex; cursor++) {
@@ -33721,15 +34059,28 @@ function tryParseLambdaParameters(tokens, start, pairs, lexed) {
33721
34059
  segment[0]?.start ?? nameToken.start,
33722
34060
  nameToken.end
33723
34061
  ),
33724
- scopeStart: hasBlockBody && bodyOpen ? bodyOpen.end : bodyOpen?.start ?? arrow.end,
33725
- scopeEnd,
34062
+ scopeStart: body.start,
34063
+ scopeEnd: body.end,
33726
34064
  lambdaParameter: true,
33727
34065
  lambdaParameterIndex: locals.length
33728
34066
  });
33729
34067
  }
33730
34068
  segmentStart = cursor + 1;
33731
34069
  }
33732
- return { locals, endTokenIndex: closeIndex };
34070
+ return { locals, body, endTokenIndex: closeIndex };
34071
+ }
34072
+ function lambdaBodySpan(tokens, arrowIndex, pairs, lexed) {
34073
+ const arrow = tokens[arrowIndex];
34074
+ const bodyOpen = tokens[arrowIndex + 1];
34075
+ if (bodyOpen?.kind === "punctuation" && bodyOpen.text === "{") {
34076
+ const closeIndex = pairs.get(arrowIndex + 1);
34077
+ const close = closeIndex === void 0 ? void 0 : tokens[closeIndex];
34078
+ return { start: bodyOpen.end, end: close?.start ?? lexed.end };
34079
+ }
34080
+ return {
34081
+ start: arrow?.end ?? lexed.end,
34082
+ end: lambdaExpressionScopeEnd(tokens, arrowIndex + 1, pairs, lexed.end)
34083
+ };
33733
34084
  }
33734
34085
  function lambdaExpressionScopeEnd(tokens, bodyStart, pairs, sourceEnd) {
33735
34086
  for (let cursor = bodyStart; cursor < tokens.length; cursor++) {
@@ -33746,6 +34097,9 @@ function lambdaExpressionScopeEnd(tokens, bodyStart, pairs, sourceEnd) {
33746
34097
  }
33747
34098
  return sourceEnd;
33748
34099
  }
34100
+ function isCallTypeArgumentToken(token) {
34101
+ return token.kind === "identifier" || token.kind === "type" || [".", ",", "?", "[", "]"].includes(token.text);
34102
+ }
33749
34103
  function callOpenParenIndex(tokens, nameIndex) {
33750
34104
  if (tokens[nameIndex + 1]?.text === "(") return nameIndex + 1;
33751
34105
  if (tokens[nameIndex + 1]?.text !== "<") return -1;
@@ -33754,8 +34108,7 @@ function callOpenParenIndex(tokens, nameIndex) {
33754
34108
  const token = tokens[cursor];
33755
34109
  if (token.text === "<") depth++;
33756
34110
  else if (/^>+$/.test(token.text)) depth -= token.text.length;
33757
- else if (token.kind !== "identifier" && token.kind !== "type" && ![".", ",", "?", "[", "]"].includes(token.text))
33758
- return -1;
34111
+ else if (!isCallTypeArgumentToken(token)) return -1;
33759
34112
  if (depth === 0) return tokens[cursor + 1]?.text === "(" ? cursor + 1 : -1;
33760
34113
  if (depth < 0) return -1;
33761
34114
  }
@@ -33777,15 +34130,84 @@ function callTypeArgumentTokens(tokens, nameIndex, openIndex) {
33777
34130
  }
33778
34131
  return argumentsTokens;
33779
34132
  }
33780
- function indexReferences(tokens, declarations, contextualKeywords) {
34133
+ function enclosingOpenerIndex(tokens) {
34134
+ const enclosing = new Int32Array(tokens.length);
34135
+ const openers = [];
34136
+ for (let index = 0; index < tokens.length; index++) {
34137
+ enclosing[index] = openers.length ? openers[openers.length - 1] : -1;
34138
+ const token = tokens[index];
34139
+ if (token.kind !== "punctuation") continue;
34140
+ if (token.text === "(" || token.text === "[" || token.text === "{") {
34141
+ openers.push(index);
34142
+ } else if (token.text === ")" || token.text === "]" || token.text === "}") {
34143
+ openers.pop();
34144
+ }
34145
+ }
34146
+ return enclosing;
34147
+ }
34148
+ function isContextualNew(token, previous, next) {
34149
+ return token.text === NEOSCRIPT_CONSTRUCTOR_KEYWORD && previous?.text !== "." && previous?.text !== "?." && (next?.kind === "identifier" || next?.kind === "type" || next?.text === "(" || next?.text === "{");
34150
+ }
34151
+ function objectInitializerBraceIndex(tokens, newIndex, pairs) {
34152
+ let cursor = newIndex + 1;
34153
+ const opener = tokens[cursor]?.text;
34154
+ if (opener !== "(" && opener !== "{") {
34155
+ const typeEnd = new Parser(tokens, cursor).typeEnd();
34156
+ if (typeEnd >= 0) cursor = typeEnd;
34157
+ }
34158
+ if (tokens[cursor]?.text === "(") {
34159
+ const close = pairs.get(cursor);
34160
+ if (close === void 0) return -1;
34161
+ cursor = close + 1;
34162
+ }
34163
+ return tokens[cursor]?.text === "{" ? cursor : -1;
34164
+ }
34165
+ function indexReferences(tokens, pairs, declarations, contextualKeywords, negations, initializers) {
33781
34166
  const references = [];
34167
+ const enclosing = enclosingOpenerIndex(tokens);
34168
+ const initializerBraces = /* @__PURE__ */ new Set();
34169
+ const patternBindings = /* @__PURE__ */ new Set();
33782
34170
  for (let index = 0; index < tokens.length; index++) {
33783
34171
  const token = tokens[index];
33784
- if (!token || token.kind !== "identifier" && token.text !== "base")
34172
+ if (!token) continue;
34173
+ if (token.kind === "keyword" && token.text === "is") {
34174
+ const not = tokens[index + 1];
34175
+ let typeStart = index + 1;
34176
+ if (not?.text === "not") {
34177
+ negations.push(not.range);
34178
+ typeStart = index + 2;
34179
+ index++;
34180
+ }
34181
+ const end = new Parser(tokens, typeStart).typeEnd({
34182
+ conditionalQuestion: true
34183
+ });
34184
+ if (end >= 0 && tokens[end]?.kind === "identifier") {
34185
+ patternBindings.add(end);
34186
+ }
33785
34187
  continue;
34188
+ }
34189
+ if (token.kind !== "identifier" && token.text !== "base") continue;
34190
+ const previous = tokens[index - 1];
34191
+ const next = tokens[index + 1];
34192
+ if (isContextualNew(token, previous, next)) {
34193
+ const brace = objectInitializerBraceIndex(tokens, index, pairs);
34194
+ if (brace >= 0) {
34195
+ initializerBraces.add(brace);
34196
+ initializers.push({
34197
+ constructorStart: token.start,
34198
+ braceStart: tokens[brace].start
34199
+ });
34200
+ }
34201
+ continue;
34202
+ }
34203
+ const opener = enclosing[index];
34204
+ if (opener >= 0 && (previous?.text === "," || index - 1 === opener)) {
34205
+ const label = next?.text === ":" && tokens[opener]?.text === "(";
34206
+ const key = next?.kind === "operator" && next.text === "=" && initializerBraces.has(opener);
34207
+ if (label || key) continue;
34208
+ }
33786
34209
  const declarationKey = `${token.range.start.line}:${token.range.start.character}`;
33787
34210
  if (contextualKeywords.has(declarationKey)) continue;
33788
- const previous = tokens[index - 1];
33789
34211
  references.push({
33790
34212
  name: token.text,
33791
34213
  range: token.range,
@@ -33793,7 +34215,7 @@ function indexReferences(tokens, declarations, contextualKeywords) {
33793
34215
  end: token.end,
33794
34216
  member: previous?.kind === "punctuation" && previous.text === "." || previous?.kind === "operator" && previous.text === "?.",
33795
34217
  call: callOpenParenIndex(tokens, index) >= 0,
33796
- declaration: declarations.has(declarationKey)
34218
+ declaration: declarations.has(declarationKey) || patternBindings.has(index)
33797
34219
  });
33798
34220
  }
33799
34221
  return references;
@@ -33806,12 +34228,18 @@ function indexCalls(tokens, pairs, lexed) {
33806
34228
  const open = tokens[openIndex];
33807
34229
  if (!name || name.kind !== "identifier") continue;
33808
34230
  if (!open || open.kind !== "punctuation" || open.text !== "(") continue;
33809
- const contextualKeyword = tokens[index - 1];
33810
- const constructor = contextualKeyword?.kind === "identifier" && contextualKeyword.text === NEOSCRIPT_CONSTRUCTOR_KEYWORD;
34231
+ const previous = tokens[index - 1];
34232
+ const targetTyped = isContextualNew(name, previous, open);
34233
+ let contextualKeyword;
34234
+ if (targetTyped) contextualKeyword = name;
34235
+ else if (previous?.kind === "identifier" && previous.text === NEOSCRIPT_CONSTRUCTOR_KEYWORD)
34236
+ contextualKeyword = previous;
33811
34237
  const closeIndex = pairs.get(openIndex);
33812
34238
  const close = closeIndex === void 0 ? void 0 : tokens[closeIndex];
33813
34239
  const ranges = [];
34240
+ const names = [];
33814
34241
  let segmentStart = open.end;
34242
+ let segmentStartIndex = openIndex + 1;
33815
34243
  let nested = 0;
33816
34244
  const limit = closeIndex ?? tokens.length;
33817
34245
  for (let cursor = openIndex + 1; cursor < limit; cursor++) {
@@ -33823,17 +34251,21 @@ function indexCalls(tokens, pairs, lexed) {
33823
34251
  nested--;
33824
34252
  if (nested === 0 && token.kind === "punctuation" && token.text === ",") {
33825
34253
  ranges.push(lexed.source.range(segmentStart, token.start));
34254
+ names.push(callArgumentLabel(tokens, segmentStartIndex, cursor));
33826
34255
  segmentStart = token.end;
34256
+ segmentStartIndex = cursor + 1;
33827
34257
  }
33828
34258
  }
33829
34259
  if (segmentStart < (close?.start ?? lexed.end)) {
33830
34260
  ranges.push(lexed.source.range(segmentStart, close?.start ?? lexed.end));
34261
+ names.push(callArgumentLabel(tokens, segmentStartIndex, limit));
33831
34262
  }
33832
34263
  calls.push({
33833
- kind: constructor ? "constructor" : "function",
34264
+ kind: contextualKeyword ? "constructor" : "function",
33834
34265
  name: name.text,
33835
34266
  nameRange: name.range,
33836
- ...constructor ? { contextualKeywordRange: contextualKeyword.range } : {},
34267
+ ...contextualKeyword ? { contextualKeywordRange: contextualKeyword.range } : {},
34268
+ ...targetTyped ? { targetTyped: true } : {},
33837
34269
  ...openIndex > index + 1 ? {
33838
34270
  typeArgumentTokens: callTypeArgumentTokens(
33839
34271
  tokens,
@@ -33843,11 +34275,17 @@ function indexCalls(tokens, pairs, lexed) {
33843
34275
  } : {},
33844
34276
  openParenOffset: open.start,
33845
34277
  ...close ? { closeParenOffset: close.end } : {},
33846
- argumentRanges: ranges
34278
+ argumentRanges: ranges,
34279
+ argumentNames: names
33847
34280
  });
33848
34281
  }
33849
34282
  return calls;
33850
34283
  }
34284
+ function callArgumentLabel(tokens, start, end) {
34285
+ const name = tokens[start];
34286
+ const colon = tokens[start + 1];
34287
+ return start + 1 < end && name !== void 0 && isCallArgumentLabelToken(name) && colon?.kind === "punctuation" && colon.text === ":" ? name.text : null;
34288
+ }
33851
34289
  function validateTerminatedStatements(tokens, diagnostics) {
33852
34290
  for (let index = 0; index < tokens.length; index++) {
33853
34291
  const token = tokens[index];
@@ -33892,36 +34330,44 @@ function validateTerminatedStatements(tokens, diagnostics) {
33892
34330
  }
33893
34331
  }
33894
34332
  }
33895
- function containingBraceRange(tokens, tokenIndex, documentEnd) {
33896
- let depth = 0;
33897
- let start = 0;
33898
- for (let index = tokenIndex - 1; index >= 0; index--) {
34333
+ function braceScopeIndex(tokens, documentEnd) {
34334
+ const openBefore = new Int32Array(tokens.length);
34335
+ const closeOf = /* @__PURE__ */ new Map();
34336
+ const unmatchedCloses = [];
34337
+ const stack = [];
34338
+ for (let index = 0; index < tokens.length; index++) {
34339
+ openBefore[index] = stack.at(-1) ?? -1;
33899
34340
  const token = tokens[index];
33900
- if (!token || token.kind !== "punctuation") continue;
33901
- if (token.text === "}") depth++;
33902
- if (token.text === "{") {
33903
- if (depth === 0) {
33904
- start = token.end;
33905
- break;
33906
- }
33907
- depth--;
34341
+ if (token.kind !== "punctuation") continue;
34342
+ if (token.text === "{") stack.push(index);
34343
+ else if (token.text === "}") {
34344
+ const open = stack.pop();
34345
+ if (open === void 0) unmatchedCloses.push(index);
34346
+ else closeOf.set(open, index);
34347
+ }
34348
+ }
34349
+ return (tokenIndex) => {
34350
+ const open = openBefore[tokenIndex] ?? -1;
34351
+ if (open >= 0) {
34352
+ const close2 = closeOf.get(open);
34353
+ return {
34354
+ start: tokens[open].end,
34355
+ end: close2 === void 0 ? documentEnd : tokens[close2].start
34356
+ };
33908
34357
  }
33909
- }
33910
- depth = 0;
33911
- let end = documentEnd;
33912
- for (let index = tokenIndex + 1; index < tokens.length; index++) {
33913
- const token = tokens[index];
33914
- if (!token || token.kind !== "punctuation") continue;
33915
- if (token.text === "{") depth++;
33916
- if (token.text === "}") {
33917
- if (depth === 0) {
33918
- end = token.start;
33919
- break;
33920
- }
33921
- depth--;
34358
+ let low = 0;
34359
+ let high = unmatchedCloses.length;
34360
+ while (low < high) {
34361
+ const mid = low + high >> 1;
34362
+ if (unmatchedCloses[mid] > tokenIndex) high = mid;
34363
+ else low = mid + 1;
33922
34364
  }
33923
- }
33924
- return { start, end };
34365
+ const close = unmatchedCloses[low];
34366
+ return {
34367
+ start: 0,
34368
+ end: close === void 0 ? documentEnd : tokens[close].start
34369
+ };
34370
+ };
33925
34371
  }
33926
34372
  function tryParseCatchParameter(tokens, start, pairs, lexed) {
33927
34373
  const keyword = tokens[start];
@@ -33969,7 +34415,7 @@ function tryParseCatchParameter(tokens, start, pairs, lexed) {
33969
34415
  resumeTokenIndex: closeIndex
33970
34416
  };
33971
34417
  }
33972
- function tryParseLoopLocal(tokens, start, pairs, lexed, diagnostics) {
34418
+ function tryParseLoopLocal(tokens, start, pairs, lexed, diagnostics, braceScope) {
33973
34419
  const keyword = tokens[start];
33974
34420
  if (!keyword || keyword.kind !== "keyword" || keyword.text !== "for" && keyword.text !== "foreach") {
33975
34421
  return null;
@@ -33980,7 +34426,12 @@ function tryParseLoopLocal(tokens, start, pairs, lexed, diagnostics) {
33980
34426
  if (closeIndex === void 0) return null;
33981
34427
  const scopeEnd = loopBodyScopeEnd(tokens, closeIndex + 1, pairs, lexed.end);
33982
34428
  if (keyword.text === "for") {
33983
- const declaration = tryParseVariableDeclaration(tokens, start + 2, lexed);
34429
+ const declaration = tryParseVariableDeclaration(
34430
+ tokens,
34431
+ start + 2,
34432
+ lexed,
34433
+ braceScope
34434
+ );
33984
34435
  if (!declaration || declaration.endTokenIndex >= closeIndex) return null;
33985
34436
  if (declaration.missingInitializer) {
33986
34437
  diagnostics.push({
@@ -34302,6 +34753,23 @@ var COLLECTION_QUERY_METHODS = {
34302
34753
  Reverse: "none",
34303
34754
  Concat: "collection"
34304
34755
  };
34756
+ var COLLECTION_FUNCTION_ARGUMENTS = {
34757
+ Where: "predicate",
34758
+ First: "optionalPredicate",
34759
+ FirstOrDefault: "optionalPredicate",
34760
+ Select: "selector",
34761
+ Count: "optionalPredicate",
34762
+ ...COLLECTION_QUERY_METHODS
34763
+ };
34764
+ function isCollectionFunctionName(name) {
34765
+ return Object.hasOwn(COLLECTION_FUNCTION_ARGUMENTS, name);
34766
+ }
34767
+ var COLLECTION_FUNCTION_ALIASES = { Find: "FirstOrDefault" };
34768
+ function collectionFunctionContract(name) {
34769
+ if (Object.hasOwn(COLLECTION_FUNCTION_ALIASES, name))
34770
+ return COLLECTION_FUNCTION_ALIASES[name];
34771
+ return isCollectionFunctionName(name) ? name : null;
34772
+ }
34305
34773
  function isCollectionQueryName(name) {
34306
34774
  return Object.hasOwn(COLLECTION_QUERY_METHODS, name);
34307
34775
  }
@@ -36192,10 +36660,12 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
36192
36660
  statement.pos
36193
36661
  );
36194
36662
  }
36195
- if (statement.target.kind === "member" && statement.target.name === "OnChanged") {
36663
+ if (statement.target.kind === "member" && statement.target.name === NEOSCRIPT_ON_CHANGED_MEMBER) {
36196
36664
  const observed = this.resolveExpression(statement.target.receiver, scope);
36197
36665
  const observedType = neoScriptMemberLookupType(observed.type);
36198
- const declared = observedType.kind === "named" && this.project.typeById.get(observedType.typeId)?.members.some((member) => member.name === "OnChanged");
36666
+ const declared = observedType.kind === "named" && this.project.typeById.get(observedType.typeId)?.members.some(
36667
+ (member) => member.name === NEOSCRIPT_ON_CHANGED_MEMBER
36668
+ );
36199
36669
  if (!declared) {
36200
36670
  if (statement.op !== "+=" && statement.op !== "-=")
36201
36671
  throw new CompileError(ON_CHANGED_OPERATIONS_ERROR, statement.pos);
@@ -36414,12 +36884,12 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
36414
36884
  }
36415
36885
  /** `X.M.OnChanged.Clear()` empties M's listener set on X (P70, P106). */
36416
36886
  resolveChangeListenerClear(expression, scope, pos) {
36417
- if (expression.kind !== "call" || expression.callee.kind !== "member" || expression.callee.name !== "Clear" || expression.callee.receiver.kind !== "member" || expression.callee.receiver.name !== "OnChanged")
36887
+ if (expression.kind !== "call" || expression.callee.kind !== "member" || expression.callee.name !== "Clear" || expression.callee.receiver.kind !== "member" || expression.callee.receiver.name !== NEOSCRIPT_ON_CHANGED_MEMBER)
36418
36888
  return null;
36419
36889
  const onChanged = expression.callee.receiver;
36420
36890
  const observed = this.resolveExpression(onChanged.receiver, scope);
36421
36891
  const observedType = neoScriptMemberLookupType(observed.type);
36422
- if (observedType.kind === "named" && this.project.typeById.get(observedType.typeId)?.members.some((member) => member.name === "OnChanged"))
36892
+ if (observedType.kind === "named" && this.project.typeById.get(observedType.typeId)?.members.some((member) => member.name === NEOSCRIPT_ON_CHANGED_MEMBER))
36423
36893
  return null;
36424
36894
  if (expression.callee.optional)
36425
36895
  throw new CompileError(
@@ -37145,7 +37615,14 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
37145
37615
  );
37146
37616
  }
37147
37617
  case "new": {
37148
- const vector3 = this.targetTypedVectorKind(expression, expected);
37618
+ const constructed = expression.className ?? (expected?.kind === "primitive" ? expected.name : null);
37619
+ if (constructed === "Color") {
37620
+ throw new CompileError(
37621
+ "Color has no NeoScript constructor; write its components as numeric literals.",
37622
+ expression.pos
37623
+ );
37624
+ }
37625
+ const vector3 = this.constructedVectorKind(expression, constructed);
37149
37626
  if (vector3 !== null) {
37150
37627
  return this.resolveVectorConstructor(
37151
37628
  vector3,
@@ -37655,10 +38132,19 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
37655
38132
  };
37656
38133
  }
37657
38134
  resolveListLiteral(elements, scope, expected, pos) {
37658
- const expectedEntry = expected?.kind === "list" ? expected.elementType : void 0;
38135
+ const expectedEntry = expected?.kind === "list" || expected?.kind === "set" ? expected.elementType : void 0;
37659
38136
  const resolved = elements.map(
37660
38137
  (element) => this.resolveExpression(element, scope, expectedEntry)
37661
38138
  );
38139
+ if (expectedEntry !== void 0 && this.context.kind === "initializer") {
38140
+ resolved.forEach((item, index) => {
38141
+ if (isNeoScriptTypeAssignable(item.type, expectedEntry, this.project)) return;
38142
+ throw new CompileError(
38143
+ `Expected ${this.describe(expectedEntry)} but received ${this.describe(item.type)}.`,
38144
+ elements[index].pos
38145
+ );
38146
+ });
38147
+ }
37662
38148
  let entryType = expectedEntry ?? resolved[0]?.type;
37663
38149
  if (!entryType) {
37664
38150
  throw new CompileError(
@@ -37680,6 +38166,14 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
37680
38166
  }
37681
38167
  entryType = common;
37682
38168
  }
38169
+ if (expected?.kind === "set" && this.context.kind === "initializer") {
38170
+ const element = expected.elementType;
38171
+ const spelling = element.kind === "named" && this.project.typeById.get(element.typeId)?.kind === "enum" ? `.Option or ${this.describe({ ...element, nullable: false })}.Option values` : "literal values";
38172
+ throw new CompileError(
38173
+ `${this.describe(expected)} has no NeoScript literal; write its elements as ${spelling}.`,
38174
+ pos
38175
+ );
38176
+ }
37683
38177
  const type = {
37684
38178
  kind: "list",
37685
38179
  elementType: entryType
@@ -38616,7 +39110,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
38616
39110
  pos
38617
39111
  );
38618
39112
  }
38619
- if (name === "Id" && type.kind === "class") {
39113
+ if (name === NEOSCRIPT_CLASS_ID_MEMBER && type.kind === "class") {
38620
39114
  return this.keyOf(
38621
39115
  receiver,
38622
39116
  name,
@@ -38705,7 +39199,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
38705
39199
  entryUserData
38706
39200
  };
38707
39201
  }
38708
- if (name === "OnChanged")
39202
+ if (name === NEOSCRIPT_ON_CHANGED_MEMBER)
38709
39203
  throw new CompileError(ON_CHANGED_OPERATIONS_ERROR, pos);
38710
39204
  throw new CompileError(
38711
39205
  `Cannot read member '${name}' on ${this.describe(receiver.type)}`,
@@ -40202,23 +40696,12 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
40202
40696
  this.project.typeByName.get(className) ?? { declaredConstructors: [] }
40203
40697
  );
40204
40698
  }
40205
- const inferredTypes = this.inferOverloadArgumentTypes(
40699
+ const resolution = this.declaredConstructorResolution(
40206
40700
  declared,
40207
40701
  named,
40208
- expression,
40702
+ expression.args,
40209
40703
  scope
40210
40704
  );
40211
- const resolution = resolveNeoScriptDeclaredConstructorOverload(
40212
- declared,
40213
- named.map((name, index) => {
40214
- const inferred = inferredTypes?.[index];
40215
- if (!inferred) return { name };
40216
- return {
40217
- name,
40218
- matchesParameter: (parameter3) => isNeoScriptTypeAssignable(inferred, parameter3.type, this.project)
40219
- };
40220
- })
40221
- );
40222
40705
  if (resolution.kind === "resolved") return resolution.constructor;
40223
40706
  if (resolution.kind === "ambiguous") {
40224
40707
  throw new CompileError(
@@ -40231,6 +40714,38 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
40231
40714
  pos
40232
40715
  );
40233
40716
  }
40717
+ /**
40718
+ * #1310. The overload a named `new` call in an initializer expression
40719
+ * compiles against, for editor features that hold its argument expressions.
40720
+ */
40721
+ initializerConstructorOverload(declared, named, args) {
40722
+ const resolution = this.declaredConstructorResolution(
40723
+ declared,
40724
+ named,
40725
+ args,
40726
+ this.initialScope()
40727
+ );
40728
+ return resolution.kind === "resolved" ? resolution.constructor : null;
40729
+ }
40730
+ declaredConstructorResolution(declared, named, args, scope) {
40731
+ const inferredTypes = this.inferOverloadArgumentTypes(
40732
+ declared,
40733
+ named,
40734
+ args,
40735
+ scope
40736
+ );
40737
+ return resolveNeoScriptDeclaredConstructorOverload(
40738
+ declared,
40739
+ named.map((name, index) => {
40740
+ const inferred = inferredTypes?.[index];
40741
+ if (!inferred) return { name };
40742
+ return {
40743
+ name,
40744
+ matchesParameter: (parameter3) => isNeoScriptTypeAssignable(inferred, parameter3.type, this.project)
40745
+ };
40746
+ })
40747
+ );
40748
+ }
40234
40749
  /**
40235
40750
  * Types for the §6.1.1 step-2 tie-break, computed only when several
40236
40751
  * overloads share the call's name set. Expected-type inference is
@@ -40238,7 +40753,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
40238
40753
  * known — so an argument that needs it (a contextual enum option, a
40239
40754
  * target-typed `new`) simply does not participate in the tie-break.
40240
40755
  */
40241
- inferOverloadArgumentTypes(declared, named, expression, scope) {
40756
+ inferOverloadArgumentTypes(declared, named, args, scope) {
40242
40757
  const nameSetKey = neoScriptArgumentNameSetKey(named);
40243
40758
  const sharing = declared.filter(
40244
40759
  (candidate) => neoScriptArgumentNameSetKey(
@@ -40247,7 +40762,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
40247
40762
  );
40248
40763
  if (sharing.length < 2) return null;
40249
40764
  return named.map((_, index) => {
40250
- const argument2 = expression.args[index];
40765
+ const argument2 = args[index];
40251
40766
  if (!argument2) return null;
40252
40767
  try {
40253
40768
  return this.resolveExpression(argument2, scope).type;
@@ -40931,6 +41446,15 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
40931
41446
  resolveCollectionFunction(receiver, name, args, scope, pos) {
40932
41447
  const collection = collectionPartsFor(receiver);
40933
41448
  if (!collection) return null;
41449
+ const contract = collectionFunctionContract(name);
41450
+ if (contract !== null) {
41451
+ requireCollectionArguments(
41452
+ name,
41453
+ COLLECTION_FUNCTION_ARGUMENTS[contract],
41454
+ args,
41455
+ pos
41456
+ );
41457
+ }
40934
41458
  if (isCollectionQueryName(name)) {
40935
41459
  return this.resolveCollectionQuery(
40936
41460
  receiver,
@@ -40942,12 +41466,6 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
40942
41466
  );
40943
41467
  }
40944
41468
  if (name === "Count") {
40945
- if (args.length > 1) {
40946
- throw new CompileError(
40947
- `Count expects zero or one predicate, got ${args.length}.`,
40948
- pos
40949
- );
40950
- }
40951
41469
  const fn = args[0] ? this.resolveCollectionLambda(
40952
41470
  args[0],
40953
41471
  collection,
@@ -41023,7 +41541,6 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41023
41541
  );
41024
41542
  }
41025
41543
  if (name === "Where") {
41026
- requireArgCount(name, args, 1, pos);
41027
41544
  const fn = this.resolveCollectionLambda(
41028
41545
  requiredAt(args, 0),
41029
41546
  collection,
@@ -41046,12 +41563,6 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41046
41563
  };
41047
41564
  }
41048
41565
  if (name === "First" || name === "FirstOrDefault" || name === "Find") {
41049
- if (args.length > 1) {
41050
- throw new CompileError(
41051
- `${name} expects zero or one predicate, got ${args.length}.`,
41052
- pos
41053
- );
41054
- }
41055
41566
  const fn = args[0] ? this.resolveCollectionLambda(
41056
41567
  args[0],
41057
41568
  collection,
@@ -41076,7 +41587,6 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41076
41587
  };
41077
41588
  }
41078
41589
  if (name === "Select") {
41079
- requireArgCount(name, args, 1, pos);
41080
41590
  const lambda = requiredAt(args, 0);
41081
41591
  if (lambda.kind !== "lambda") {
41082
41592
  throw new CompileError("Select requires a lambda argument.", pos);
@@ -41103,16 +41613,6 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41103
41613
  return null;
41104
41614
  }
41105
41615
  resolveCollectionQuery(receiver, collection, name, args, scope, pos) {
41106
- const kind = COLLECTION_QUERY_METHODS[name];
41107
- if (kind === "optionalPredicate") {
41108
- if (args.length > 1)
41109
- throw new CompileError(
41110
- `${name} expects zero or one predicate, got ${args.length}.`,
41111
- pos
41112
- );
41113
- } else {
41114
- requireArgCount(name, args, kind === "none" ? 0 : 1, pos);
41115
- }
41116
41616
  const base = { collectionPointer: receiver.pointer };
41117
41617
  let info;
41118
41618
  let resultType = {
@@ -41278,6 +41778,8 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41278
41778
  };
41279
41779
  }
41280
41780
  resolveScalarFunction(receiver, name, args, scope, pos) {
41781
+ if (receiver.type.kind !== "primitive" || !neoScriptScalarMethod(receiver.type.name, name))
41782
+ return null;
41281
41783
  if (isPrimitive(receiver.type, "string")) {
41282
41784
  if (name === "Contains") {
41283
41785
  requireArgCount("string.Contains", args, 1, pos);
@@ -42429,27 +42931,26 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
42429
42931
  };
42430
42932
  }
42431
42933
  /**
42432
- * The vector leaf a target-typed `new(…)` constructs, or null when the
42433
- * expression is not one.
42934
+ * The vector leaf a target-typed `new(…)` or a named `new Vector2(…)`
42935
+ * constructs, or null when the expression is not one.
42434
42936
  *
42435
42937
  * A vector has fields rather than members, so neither of `new`'s two
42436
42938
  * declaration-side spellings applies to it: an argument names a component by
42437
42939
  * position and there is no member for an initializer block to settle.
42438
42940
  */
42439
- targetTypedVectorKind(expression, expected) {
42440
- if (expression.className !== null) return null;
42441
- if (expected?.kind !== "primitive") return null;
42442
- const vector3 = vectorKind(expected.name);
42941
+ constructedVectorKind(expression, constructed) {
42942
+ const vector3 = constructed === null ? null : vectorKind(constructed);
42443
42943
  if (vector3 === null) return null;
42944
+ const spelling = expression.className === null ? "new(\u2026)" : `new ${vector3}(\u2026)`;
42444
42945
  if (expression.argumentNames !== void 0) {
42445
42946
  throw new CompileError(
42446
- `${vector3} components are positional, so \`new(\u2026)\` cannot name them.`,
42947
+ `${vector3} components are positional, so \`${spelling}\` cannot name them.`,
42447
42948
  expression.pos
42448
42949
  );
42449
42950
  }
42450
42951
  if ((expression.initializer?.length ?? 0) > 0) {
42451
42952
  throw new CompileError(
42452
- `${vector3} has fields rather than members, so \`new(\u2026)\` cannot carry an initializer block. Pass every component instead.`,
42953
+ `${vector3} has fields rather than members, so \`${spelling}\` cannot carry an initializer block. Pass every component instead.`,
42453
42954
  expression.pos
42454
42955
  );
42455
42956
  }
@@ -42620,6 +43121,12 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
42620
43121
  }
42621
43122
  requireAssignable(source, target, pos, usage) {
42622
43123
  if (isNeoScriptTypeAssignable(source, target, this.project)) return;
43124
+ if (usage === "return" && this.context.kind === "initializer" && this.lambdaDepth === 0) {
43125
+ throw new CompileError(
43126
+ `Expected ${this.describe(target)} but received ${this.describe(source)}.`,
43127
+ pos
43128
+ );
43129
+ }
42623
43130
  const prefix = usage === "return" ? "Returned" : "Cannot use";
42624
43131
  throw new CompileError(
42625
43132
  `${prefix} ${this.describe(source)} ${usage === "return" ? "is not assignable to declared return type" : `as ${usage} of type`} ${this.describe(target)}`,
@@ -43894,17 +44401,6 @@ function collectionOperationValueType(expression, collection) {
43894
44401
  function isLookupSelectionCollection(expression, collection) {
43895
44402
  return collection.kind === "set" && expression.wireType?.type === 9 /* Lookup */;
43896
44403
  }
43897
- var SPRITE_DERIVED_MEMBERS = {
43898
- FileName: { kind: "primitive", name: "string" },
43899
- Name: { kind: "primitive", name: "string" },
43900
- Size: { kind: "primitive", name: "Vector2" },
43901
- Pivot: { kind: "primitive", name: "Vector2" },
43902
- Slices: {
43903
- kind: "list",
43904
- elementType: { kind: "primitive", name: "SpriteInfo" },
43905
- readOnly: true
43906
- }
43907
- };
43908
44404
  function assignableFieldList(owner) {
43909
44405
  if (!isNeoScriptStructuredLeafTypeName(owner)) return "a stored field";
43910
44406
  const names = neoScriptStructuredLeafFieldNames(owner);
@@ -43918,19 +44414,8 @@ function resolvePrimitiveMember(type, name) {
43918
44414
  );
43919
44415
  if (field) return { type: field.type, key: field.key };
43920
44416
  }
43921
- if (type.name === "SpriteInfo" && Object.prototype.hasOwnProperty.call(SPRITE_DERIVED_MEMBERS, name)) {
43922
- const derived = SPRITE_DERIVED_MEMBERS[name];
43923
- if (derived) return { type: derived, derived: true };
43924
- }
43925
- if (type.name === "AudioClipInfo") {
43926
- if (name === "url" || name === "name")
43927
- return { type: { kind: "primitive", name: "string" } };
43928
- if (name === "length")
43929
- return { type: { kind: "primitive", name: "float" } };
43930
- }
43931
- if (type.name === "NeoDialogueReference" && name === "id")
43932
- return { type: { kind: "primitive", name: "string" } };
43933
- return null;
44417
+ const derived = neoScriptPrimitiveDerivedMember(type.name, name);
44418
+ return derived ? { type: derived.type, derived: true } : null;
43934
44419
  }
43935
44420
  function isActionMemberPointer(pointer) {
43936
44421
  if (pointer.type === "staticMember" /* StaticMember */) return true;
@@ -44179,6 +44664,17 @@ function functionArityMessage(name, minimum, maximum, got) {
44179
44664
  }
44180
44665
  return `Function '${name}' expects between ${minimum} and ${maximum} arguments, got ${got}.`;
44181
44666
  }
44667
+ function requireCollectionArguments(name, shape, args, pos) {
44668
+ if (shape !== "optionalPredicate") {
44669
+ requireArgCount(name, args, shape === "none" ? 0 : 1, pos);
44670
+ return;
44671
+ }
44672
+ if (args.length <= 1) return;
44673
+ throw new CompileError(
44674
+ `${name} expects zero or one predicate, got ${args.length}.`,
44675
+ pos
44676
+ );
44677
+ }
44182
44678
  function requireArgCount(name, args, expected, pos) {
44183
44679
  if (args.length === expected) return;
44184
44680
  throw new CompileError(
@@ -44260,6 +44756,18 @@ function resolveNeoScriptType(type, context, project) {
44260
44756
  resolved = registryReference;
44261
44757
  break;
44262
44758
  }
44759
+ if (type.name === "NeoDelegate") {
44760
+ const [returnType, ...parameterTypes] = (type.typeArguments ?? []).map(
44761
+ (argument2) => resolveNeoScriptType(argument2, context, project)
44762
+ );
44763
+ if (!returnType)
44764
+ throw new CompileError(
44765
+ "NeoDelegate requires a return type argument, for example NeoDelegate<int>.",
44766
+ type.pos
44767
+ );
44768
+ resolved = { kind: "delegate", returnType, parameterTypes };
44769
+ break;
44770
+ }
44263
44771
  const named = project.typeByName.get(type.name);
44264
44772
  if (!named)
44265
44773
  throw new CompileError(
@@ -45884,7 +46392,7 @@ function manifestParameterDefault(argument2, environment, field) {
45884
46392
  const value = constantDefaultValue(declared.value, `${field}.default.value`);
45885
46393
  const type = record2(argument2.type, `${field}.type`);
45886
46394
  const kind = string(type.kind, `${field}.type.kind`);
45887
- const enumOptionName = kind === "enum" && typeof value === "string" ? manifestEnumOptionName(
46395
+ const enumOptionName2 = kind === "enum" && typeof value === "string" ? manifestEnumOptionName(
45888
46396
  string(type.enumId, `${field}.type.enumId`),
45889
46397
  value,
45890
46398
  environment
@@ -45894,7 +46402,7 @@ function manifestParameterDefault(argument2, environment, field) {
45894
46402
  displayText: neoScriptParameterDefaultDisplayText({
45895
46403
  value,
45896
46404
  kind: kind === "enum" || kind === "decimal" ? kind : "other",
45897
- ...enumOptionName === void 0 ? {} : { enumOptionName }
46405
+ ...enumOptionName2 === void 0 ? {} : { enumOptionName: enumOptionName2 }
45898
46406
  }),
45899
46407
  value
45900
46408
  }
@@ -46759,13 +47267,13 @@ function overrideBaseClass(context) {
46759
47267
  function parameterDefaultDescriptor(argument2, context) {
46760
47268
  if (argument2.defaultValue === void 0) return {};
46761
47269
  const value = argument2.defaultValue.value;
46762
- const enumOptionName = argument2.type === 8 /* Enum */ && typeof value === "string" ? analyzerEnumOptionName(argument2.enumId, value, context) : void 0;
47270
+ const enumOptionName2 = argument2.type === 8 /* Enum */ && typeof value === "string" ? analyzerEnumOptionName(argument2.enumId, value, context) : void 0;
46763
47271
  return {
46764
47272
  defaultValue: {
46765
47273
  displayText: neoScriptParameterDefaultDisplayText({
46766
47274
  value,
46767
47275
  kind: parameterDefaultSpellingKind(argument2.type),
46768
- ...enumOptionName === void 0 ? {} : { enumOptionName }
47276
+ ...enumOptionName2 === void 0 ? {} : { enumOptionName: enumOptionName2 }
46769
47277
  }),
46770
47278
  value
46771
47279
  }
@@ -48388,8 +48896,9 @@ function createContext(ctx, options) {
48388
48896
  }
48389
48897
 
48390
48898
  // ../src/database/neoscript/compile-delegate-closure.ts
48899
+ var CLOSURE_GETTER_PREFIX = "return ";
48391
48900
  function compileDelegateClosureValue(code, signature) {
48392
- const compiled = compileNSGetter(`return ${code};`, {
48901
+ const compiled = compileNSGetter(`${CLOSURE_GETTER_PREFIX}${code};`, {
48393
48902
  project: signature.project,
48394
48903
  projectFiles: [...signature.projectFiles ?? []],
48395
48904
  dialogueGroups: signature.dialogueGroups ?? [],
@@ -48407,7 +48916,8 @@ function compileDelegateClosureValue(code, signature) {
48407
48916
  returnTypeInfo: signature.returnTypeInfo,
48408
48917
  argumentTypes: [...signature.argumentTypes]
48409
48918
  },
48410
- functionName: signature.name
48919
+ functionName: signature.name,
48920
+ compilationProject: signature.compilationProject
48411
48921
  });
48412
48922
  const instruction = compiled.instructions[0];
48413
48923
  if (compiled.instructions.length !== 1 || instruction?.type !== "return" /* return */ || instruction.pointer?.type !== "value" /* value */) {
@@ -48497,7 +49007,8 @@ function compileMemberInitializerBody(args) {
48497
49007
  error,
48498
49008
  memberId: args.member.id,
48499
49009
  memberName: args.member.name,
48500
- valueId: null
49010
+ valueId: null,
49011
+ code: defaultValue.init.code
48501
49012
  });
48502
49013
  }
48503
49014
  Object.assign(defaultValue.init, { compiled });
@@ -48556,7 +49067,8 @@ function compileValueRowInitializerBody(args) {
48556
49067
  error,
48557
49068
  memberId: args.member.id,
48558
49069
  memberName: args.member.name,
48559
- valueId: args.valueId
49070
+ valueId: args.valueId,
49071
+ code: container.init.code
48560
49072
  });
48561
49073
  }
48562
49074
  Object.assign(container.init, { compiled });
@@ -48585,10 +49097,20 @@ var NeoScriptBodyCompileError = class extends Error {
48585
49097
  memberId;
48586
49098
  memberName;
48587
49099
  valueId;
49100
+ /**
49101
+ * The constructor argument the body is stored inline under, when the value
49102
+ * row carries it as creation data rather than as its own row (#1303).
49103
+ */
49104
+ argument;
49105
+ /** The exact code handed to the compiler; `bodyPosition` is measured in it. */
49106
+ code;
48588
49107
  bodyPosition;
49108
+ /** The compiler's message without its body position. */
49109
+ detail;
48589
49110
  constructor(args) {
48590
- const subject = args.valueId === null ? `Member "${args.memberName}" (${args.memberId})` : `Value row "${args.valueId}" of member "${args.memberName}" (${args.memberId})`;
48591
- const at2 = args.bodyPosition === null ? "" : ` at initializer ${args.bodyPosition}`;
49111
+ const argument2 = args.argument === void 0 ? "" : ` constructor argument "${args.argument.parameterName}"`;
49112
+ const subject = args.valueId === null ? `Member "${args.memberName}" (${args.memberId})` : `Value row "${args.valueId}"${argument2} of member "${args.memberName}" (${args.memberId})`;
49113
+ const at2 = args.bodyPosition === null ? "" : ` at initializer ${args.bodyPosition.line}:${args.bodyPosition.column}`;
48592
49114
  super(
48593
49115
  `${subject} has a NeoScript body that failed to compile${at2}: ${args.detail}`
48594
49116
  );
@@ -48596,18 +49118,24 @@ var NeoScriptBodyCompileError = class extends Error {
48596
49118
  this.memberId = args.memberId;
48597
49119
  this.memberName = args.memberName;
48598
49120
  this.valueId = args.valueId;
49121
+ this.argument = args.argument ?? null;
49122
+ this.code = args.code;
48599
49123
  this.bodyPosition = args.bodyPosition;
49124
+ this.detail = args.detail;
48600
49125
  }
48601
49126
  };
48602
49127
  function throwNamedBodyCompileFailure(args) {
48603
49128
  if (args.error instanceof NeoScriptBodyCompileError) throw args.error;
48604
49129
  const compileError = args.error instanceof CompileError ? args.error : null;
48605
49130
  const detail = args.error instanceof Error ? args.error.message : String(args.error);
49131
+ const position = compileError === null ? null : { line: compileError.line, column: compileError.column };
48606
49132
  throw new NeoScriptBodyCompileError({
48607
49133
  memberId: args.memberId,
48608
49134
  memberName: args.memberName,
48609
49135
  valueId: args.valueId,
48610
- bodyPosition: compileError === null ? null : `${compileError.line}:${compileError.column}`,
49136
+ ...args.argument === void 0 ? {} : { argument: args.argument },
49137
+ code: args.code,
49138
+ bodyPosition: position === null ? null : args.codePosition?.(position) ?? position,
48611
49139
  detail: compileError === null ? detail : detail.replace(
48612
49140
  new RegExp(`^${compileError.line}:${compileError.column}: `),
48613
49141
  ""
@@ -55878,79 +56406,9 @@ var INITIALIZER_KEY_PLACEHOLDER = new RegExp(
55878
56406
  "g"
55879
56407
  );
55880
56408
 
55881
- // ../packages/neoscript-language/src/project-schema-contract.generated.ts
55882
- var PROJECT_FILE_UPLOAD_BATCH_SIZE = 32;
55883
-
55884
- // src/project-source/lower-configuration.ts
55885
- var wireEnumOptions = () => (options) => options;
55886
- var TEXTURE_TYPE_WIRE_OPTIONS = wireEnumOptions()([
55887
- "default",
55888
- "normal-map",
55889
- "editor-gui-and-legacy-gui",
55890
- "sprite",
55891
- "cursor",
55892
- "cookie",
55893
- "lightmap",
55894
- "single-channel"
55895
- ]);
55896
- var ALPHA_SOURCE_WIRE_OPTIONS = wireEnumOptions()(["none", "input-texture-alpha", "from-gray-scale"]);
55897
- var NON_POWER_OF_TWO_SCALE_WIRE_OPTIONS = wireEnumOptions()(["none", "to-nearest", "to-larger", "to-smaller"]);
55898
- var MIP_MAP_FILTERING_WIRE_OPTIONS = wireEnumOptions()(["box", "kaiser"]);
55899
- var WRAP_MODE_WIRE_OPTIONS = wireEnumOptions()(["repeat", "clamp", "mirror", "mirror-once", "per-axis"]);
55900
- var FILTER_MODE_WIRE_OPTIONS = wireEnumOptions()(["point", "bilinear", "trilinear"]);
55901
- var RESIZE_ALGORITHM_WIRE_OPTIONS = wireEnumOptions()(["mitchell", "bilinear"]);
55902
- var TEXTURE_COMPRESSION_WIRE_OPTIONS = wireEnumOptions()(["none", "low-quality", "normal-quality", "high-quality"]);
55903
- var PLATFORM_FORMAT_WIRE_OPTIONS = wireEnumOptions()([
55904
- "automatic",
55905
- "rgba-compressed-dxt5-bc3",
55906
- "rgb-compressed-dxt1-bc1",
55907
- "rgba-32-bit",
55908
- "rgb-24-bit"
55909
- ]);
55910
- var SPRITE_MODE_WIRE_OPTIONS = wireEnumOptions()(["single", "multiple", "polygon"]);
55911
- var MESH_TYPE_WIRE_OPTIONS = wireEnumOptions()(["full-rect", "tight"]);
55912
- var PIVOT_ALIGNMENT_WIRE_OPTIONS = wireEnumOptions()([
55913
- "center",
55914
- "top-left",
55915
- "top-center",
55916
- "top-right",
55917
- "left-center",
55918
- "right-center",
55919
- "bottom-left",
55920
- "bottom-center",
55921
- "bottom-right",
55922
- "custom"
55923
- ]);
55924
- var SLICE_TYPE_WIRE_OPTIONS = wireEnumOptions()(["grid-by-cell-size"]);
55925
- var SLICE_NAMING_ORDER_WIRE_OPTIONS = wireEnumOptions()(["row-major", "column-major"]);
55926
- var NORMAL_MAP_FILTERING_WIRE_OPTIONS = wireEnumOptions()(["sharp", "smooth"]);
55927
- var COOKIE_LIGHT_TYPE_WIRE_OPTIONS = wireEnumOptions()(["spot", "directional", "point"]);
55928
- var SINGLE_CHANNEL_COMPONENT_WIRE_OPTIONS = wireEnumOptions()(["alpha", "red"]);
55929
- var SWIZZLE_WIRE_OPTIONS = wireEnumOptions()(["red", "green", "blue", "alpha", "zero", "one"]);
55930
- var AUDIO_LOAD_TYPE_WIRE_OPTIONS = wireEnumOptions()(["decompress-on-load", "compressed-in-memory", "streaming"]);
55931
- var AUDIO_COMPRESSION_FORMAT_WIRE_OPTIONS = wireEnumOptions()(["pcm", "adpcm", "vorbis"]);
55932
- var AUDIO_SAMPLE_RATE_WIRE_OPTIONS = wireEnumOptions()(["preserve-sample-rate", "optimize-sample-rate", "override-sample-rate"]);
55933
-
55934
- // src/project-source/lower-relations.ts
55935
- var RELATION_KIND_BY_PROPERTY = /* @__PURE__ */ new Map([
55936
- ["tileImports", "world.grid.tile-import"],
55937
- ["objectImports", "world.grid.object-import"],
55938
- ["tileLayers", "world.grid.tile-layer"],
55939
- ["objectLayers", "world.grid.object-layer"]
55940
- ]);
55941
- var SPECIALIZED_RELATION_KINDS = /* @__PURE__ */ new Set([
55942
- ...RELATION_KIND_BY_PROPERTY.values(),
55943
- "world.tile.compatible-layer",
55944
- "world.tile.default-layer",
55945
- "world.object.compatible-layer",
55946
- "world.object.default-layer",
55947
- "world.tile-layer-link.target",
55948
- "world.object-layer-link.target"
55949
- ]);
55950
-
55951
56409
  // ../packages/manifest/schema-contract/registry.mjs
55952
56410
  var PROJECT_SCHEMA_CONTRACT = Object.freeze({
55953
- cliVersion: "0.76.0",
56411
+ cliVersion: "0.76.2",
55954
56412
  projectFileUploadBatchSize: 32,
55955
56413
  documentRecords: {
55956
56414
  member: {
@@ -57384,6 +57842,76 @@ var PROJECT_SCHEMA_CONTRACT = Object.freeze({
57384
57842
  }
57385
57843
  });
57386
57844
 
57845
+ // ../packages/neoscript-language/src/project-schema-contract.generated.ts
57846
+ var PROJECT_FILE_UPLOAD_BATCH_SIZE = 32;
57847
+
57848
+ // src/project-source/lower-configuration.ts
57849
+ var wireEnumOptions = () => (options) => options;
57850
+ var TEXTURE_TYPE_WIRE_OPTIONS = wireEnumOptions()([
57851
+ "default",
57852
+ "normal-map",
57853
+ "editor-gui-and-legacy-gui",
57854
+ "sprite",
57855
+ "cursor",
57856
+ "cookie",
57857
+ "lightmap",
57858
+ "single-channel"
57859
+ ]);
57860
+ var ALPHA_SOURCE_WIRE_OPTIONS = wireEnumOptions()(["none", "input-texture-alpha", "from-gray-scale"]);
57861
+ var NON_POWER_OF_TWO_SCALE_WIRE_OPTIONS = wireEnumOptions()(["none", "to-nearest", "to-larger", "to-smaller"]);
57862
+ var MIP_MAP_FILTERING_WIRE_OPTIONS = wireEnumOptions()(["box", "kaiser"]);
57863
+ var WRAP_MODE_WIRE_OPTIONS = wireEnumOptions()(["repeat", "clamp", "mirror", "mirror-once", "per-axis"]);
57864
+ var FILTER_MODE_WIRE_OPTIONS = wireEnumOptions()(["point", "bilinear", "trilinear"]);
57865
+ var RESIZE_ALGORITHM_WIRE_OPTIONS = wireEnumOptions()(["mitchell", "bilinear"]);
57866
+ var TEXTURE_COMPRESSION_WIRE_OPTIONS = wireEnumOptions()(["none", "low-quality", "normal-quality", "high-quality"]);
57867
+ var PLATFORM_FORMAT_WIRE_OPTIONS = wireEnumOptions()([
57868
+ "automatic",
57869
+ "rgba-compressed-dxt5-bc3",
57870
+ "rgb-compressed-dxt1-bc1",
57871
+ "rgba-32-bit",
57872
+ "rgb-24-bit"
57873
+ ]);
57874
+ var SPRITE_MODE_WIRE_OPTIONS = wireEnumOptions()(["single", "multiple", "polygon"]);
57875
+ var MESH_TYPE_WIRE_OPTIONS = wireEnumOptions()(["full-rect", "tight"]);
57876
+ var PIVOT_ALIGNMENT_WIRE_OPTIONS = wireEnumOptions()([
57877
+ "center",
57878
+ "top-left",
57879
+ "top-center",
57880
+ "top-right",
57881
+ "left-center",
57882
+ "right-center",
57883
+ "bottom-left",
57884
+ "bottom-center",
57885
+ "bottom-right",
57886
+ "custom"
57887
+ ]);
57888
+ var SLICE_TYPE_WIRE_OPTIONS = wireEnumOptions()(["grid-by-cell-size"]);
57889
+ var SLICE_NAMING_ORDER_WIRE_OPTIONS = wireEnumOptions()(["row-major", "column-major"]);
57890
+ var NORMAL_MAP_FILTERING_WIRE_OPTIONS = wireEnumOptions()(["sharp", "smooth"]);
57891
+ var COOKIE_LIGHT_TYPE_WIRE_OPTIONS = wireEnumOptions()(["spot", "directional", "point"]);
57892
+ var SINGLE_CHANNEL_COMPONENT_WIRE_OPTIONS = wireEnumOptions()(["alpha", "red"]);
57893
+ var SWIZZLE_WIRE_OPTIONS = wireEnumOptions()(["red", "green", "blue", "alpha", "zero", "one"]);
57894
+ var AUDIO_LOAD_TYPE_WIRE_OPTIONS = wireEnumOptions()(["decompress-on-load", "compressed-in-memory", "streaming"]);
57895
+ var AUDIO_COMPRESSION_FORMAT_WIRE_OPTIONS = wireEnumOptions()(["pcm", "adpcm", "vorbis"]);
57896
+ var AUDIO_SAMPLE_RATE_WIRE_OPTIONS = wireEnumOptions()(["preserve-sample-rate", "optimize-sample-rate", "override-sample-rate"]);
57897
+
57898
+ // src/project-source/lower-relations.ts
57899
+ var RELATION_KIND_BY_PROPERTY = /* @__PURE__ */ new Map([
57900
+ ["tileImports", "world.grid.tile-import"],
57901
+ ["objectImports", "world.grid.object-import"],
57902
+ ["tileLayers", "world.grid.tile-layer"],
57903
+ ["objectLayers", "world.grid.object-layer"]
57904
+ ]);
57905
+ var SPECIALIZED_RELATION_KINDS = /* @__PURE__ */ new Set([
57906
+ ...RELATION_KIND_BY_PROPERTY.values(),
57907
+ "world.tile.compatible-layer",
57908
+ "world.tile.default-layer",
57909
+ "world.object.compatible-layer",
57910
+ "world.object.default-layer",
57911
+ "world.tile-layer-link.target",
57912
+ "world.object-layer-link.target"
57913
+ ]);
57914
+
57387
57915
  // src/project-source/workspace-status-core.ts
57388
57916
  var ANIMATION_DOCUMENT_RECORD_KINDS = [
57389
57917
  ProjectRecordKind.Project,