@neocompose/cli 0.76.1 → 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
  },
@@ -24849,6 +24969,11 @@ function evaluateInitializerInContext(init, member, ctx, createdValues, argument
24849
24969
  sessionValueExport: "defer"
24850
24970
  }
24851
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;
24852
24977
  } finally {
24853
24978
  closeFrame();
24854
24979
  }
@@ -29419,11 +29544,8 @@ var Parser = class _Parser {
29419
29544
  * always opens with a type expression, which can be:
29420
29545
  * - A primitive keyword: int / float / bool / string
29421
29546
  * - `Dictionary` keyword followed by `<`
29422
- * - An identifier (Class or Enum) with `[]` suffix or
29423
- * followed by another identifier (the var name).
29424
- *
29425
- * We don't fully parse the type here — we just decide whether to commit
29426
- * 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 `=`.
29427
29549
  */
29428
29550
  looksLikeVarDecl() {
29429
29551
  const t = this.peek();
@@ -29440,25 +29562,53 @@ var Parser = class _Parser {
29440
29562
  return true;
29441
29563
  }
29442
29564
  if (!isIdentifier(t)) return false;
29443
- let j = this.i + 1;
29444
- const tk = (k) => this.tokens[k];
29445
- while (tk(j)?.kind === "punctuation" && tk(j)?.text === "[" && tk(j + 1)?.kind === "punctuation" && tk(j + 1)?.text === "]") {
29446
- j += 2;
29447
- }
29448
- if (tk(j)?.kind === "operator" && tk(j)?.text === "?") {
29449
- j += 1;
29450
- }
29451
- const name = tk(j);
29452
- if (name !== void 0 && isIdentifier(name) && tk(j + 1)?.kind === "operator" && tk(j + 1)?.text === "=") {
29453
- 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;
29454
29585
  }
29455
- 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;
29456
29603
  }
29457
29604
  // ------------------------------------------------------------------
29458
29605
  // Types
29459
29606
  // ------------------------------------------------------------------
29460
29607
  /** Parses a type annotation (used in varDecls and Dictionary generics). */
29461
29608
  parseType(options = {}) {
29609
+ return this.parseTypeOrFail(options);
29610
+ }
29611
+ parseTypeOrFail(options) {
29462
29612
  const startPos = at(this.peek());
29463
29613
  let inner;
29464
29614
  const t = this.peek();
@@ -29472,17 +29622,18 @@ var Parser = class _Parser {
29472
29622
  };
29473
29623
  } else if (t.kind === "type" && (t.text === "Dictionary" || t.text === "List" || t.text === "Set")) {
29474
29624
  this.next();
29475
- this.expect("operator", "<");
29625
+ if (!this.expectTypeToken("operator", "<")) return null;
29476
29626
  if (t.text === "Dictionary") {
29477
- const key = this.parseType();
29627
+ const key = this.parseTypeOrFail({});
29628
+ if (!key) return null;
29478
29629
  if (this.peek().text === ">")
29479
- throw new CompileError(
29630
+ return this.typeFailure(
29480
29631
  "Dictionary requires a key type and a value type, for example Dictionary<string, int>.",
29481
- at(this.peek())
29632
+ this.peek()
29482
29633
  );
29483
- this.expect("punctuation", ",");
29484
- const value = this.parseType();
29485
- this.expect("operator", ">");
29634
+ if (!this.expectTypeToken("punctuation", ",")) return null;
29635
+ const value = this.parseTypeOrFail({});
29636
+ if (!value || !this.expectTypeToken("operator", ">")) return null;
29486
29637
  inner = {
29487
29638
  kind: "dict",
29488
29639
  key,
@@ -29491,8 +29642,8 @@ var Parser = class _Parser {
29491
29642
  pos: startPos
29492
29643
  };
29493
29644
  } else {
29494
- const element = this.parseType();
29495
- this.expect("operator", ">");
29645
+ const element = this.parseTypeOrFail({});
29646
+ if (!element || !this.expectTypeToken("operator", ">")) return null;
29496
29647
  inner = {
29497
29648
  kind: t.text === "List" ? "list" : "set",
29498
29649
  element,
@@ -29504,10 +29655,12 @@ var Parser = class _Parser {
29504
29655
  this.next();
29505
29656
  const typeArguments = [];
29506
29657
  if (this.eat("operator", "<")) {
29507
- typeArguments.push(this.parseType());
29508
- while (this.eat("punctuation", ","))
29509
- typeArguments.push(this.parseType());
29510
- 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;
29511
29664
  }
29512
29665
  inner = {
29513
29666
  kind: "named",
@@ -29517,7 +29670,7 @@ var Parser = class _Parser {
29517
29670
  pos: startPos
29518
29671
  };
29519
29672
  } else {
29520
- throw new CompileError(`Expected a type, got ${describeToken(t)}`, at(t));
29673
+ return this.typeFailure(`Expected a type, got ${describeToken(t)}`, t);
29521
29674
  }
29522
29675
  while (this.peek().kind === "punctuation" && this.peek().text === "[" && this.peek(1).kind === "punctuation" && this.peek(1).text === "]") {
29523
29676
  const arrPos = at(this.peek());
@@ -29536,6 +29689,14 @@ var Parser = class _Parser {
29536
29689
  }
29537
29690
  return inner;
29538
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
+ }
29539
29700
  /**
29540
29701
  * `is T ? a : b` is ambiguous at the token level because `?` is also the
29541
29702
  * nullable type suffix. A colon at the same delimiter depth makes it the
@@ -29890,7 +30051,7 @@ var Parser = class _Parser {
29890
30051
  }
29891
30052
  while (true) {
29892
30053
  let name = null;
29893
- 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 === ":") {
29894
30055
  name = this.next().text;
29895
30056
  this.next();
29896
30057
  }
@@ -30373,6 +30534,9 @@ function at(token) {
30373
30534
  function tokenMatches(token, kind, text) {
30374
30535
  return (kind === "identifier" ? isIdentifier(token) : token.kind === kind) && (text === void 0 || token.text === text);
30375
30536
  }
30537
+ function isCallArgumentLabelToken(token) {
30538
+ return isIdentifier(token) || token.kind === "keyword" && (token.text === "default" || isValidNeoProjectIdentifier(token.text));
30539
+ }
30376
30540
  function isIdentifier(token) {
30377
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";
30378
30542
  }
@@ -32976,6 +33140,9 @@ function evaluateMemberInitializer(args) {
32976
33140
  } catch (error) {
32977
33141
  if (error instanceof NSGetterRuntimeError) {
32978
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;
32979
33146
  }
32980
33147
  throw error;
32981
33148
  }
@@ -33240,6 +33407,9 @@ function buildNeoScriptEditorIndex(lexed, kind) {
33240
33407
  const references = [];
33241
33408
  const calls = [];
33242
33409
  const switches = [];
33410
+ const lambdaBodies = [];
33411
+ const contextualKeywordRanges = [];
33412
+ const objectInitializers = [];
33243
33413
  for (const executable of executableRegions) {
33244
33414
  const executablePairs = pairBrackets(executable);
33245
33415
  const regionSwitches = indexSwitchStatements(
@@ -33249,7 +33419,13 @@ function buildNeoScriptEditorIndex(lexed, kind) {
33249
33419
  diagnostics
33250
33420
  );
33251
33421
  const regionLocals = applySwitchSectionScopes(
33252
- indexLocals(executable, executablePairs, lexed, diagnostics),
33422
+ indexLocals(
33423
+ executable,
33424
+ executablePairs,
33425
+ lexed,
33426
+ diagnostics,
33427
+ lambdaBodies
33428
+ ),
33253
33429
  regionSwitches,
33254
33430
  lexed
33255
33431
  );
@@ -33260,24 +33436,36 @@ function buildNeoScriptEditorIndex(lexed, kind) {
33260
33436
  )
33261
33437
  );
33262
33438
  const contextualKeywords = new Set(
33263
- [
33264
- ...regionLocals.flatMap(
33265
- (local) => local.contextualKeywordRange ? [local.contextualKeywordRange] : []
33266
- ),
33267
- ...regionCalls.flatMap(
33268
- (call) => call.contextualKeywordRange ? [call.contextualKeywordRange] : []
33269
- )
33270
- ].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}`)
33271
33442
  );
33272
33443
  locals.push(...regionLocals);
33273
33444
  references.push(
33274
- ...indexReferences(executable, declarations, contextualKeywords)
33445
+ ...indexReferences(
33446
+ executable,
33447
+ executablePairs,
33448
+ declarations,
33449
+ contextualKeywords,
33450
+ contextualKeywordRanges,
33451
+ objectInitializers
33452
+ )
33275
33453
  );
33276
33454
  calls.push(...regionCalls);
33277
33455
  switches.push(...regionSwitches);
33278
33456
  validateTerminatedStatements(executable, diagnostics);
33279
33457
  }
33280
- 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
+ };
33281
33469
  }
33282
33470
  function indexUnits(tokens, pairs, kind, lexed) {
33283
33471
  if (kind !== "property") {
@@ -33694,8 +33882,9 @@ function duplicateUnitDiagnostic(label, units, diagnostics) {
33694
33882
  ]
33695
33883
  });
33696
33884
  }
33697
- function indexLocals(tokens, pairs, lexed, diagnostics) {
33885
+ function indexLocals(tokens, pairs, lexed, diagnostics, lambdaBodies) {
33698
33886
  const locals = [];
33887
+ const braceScope = braceScopeIndex(tokens, lexed.end);
33699
33888
  for (let index = 0; index < tokens.length; index++) {
33700
33889
  const caught = tryParseCatchParameter(tokens, index, pairs, lexed);
33701
33890
  if (caught) {
@@ -33703,7 +33892,14 @@ function indexLocals(tokens, pairs, lexed, diagnostics) {
33703
33892
  index = caught.resumeTokenIndex;
33704
33893
  continue;
33705
33894
  }
33706
- 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
+ );
33707
33903
  if (loop) {
33708
33904
  locals.push(...loop.locals);
33709
33905
  index = loop.resumeTokenIndex;
@@ -33712,10 +33908,16 @@ function indexLocals(tokens, pairs, lexed, diagnostics) {
33712
33908
  const lambda = tryParseLambdaParameters(tokens, index, pairs, lexed);
33713
33909
  if (lambda) {
33714
33910
  locals.push(...lambda.locals);
33911
+ lambdaBodies.push(lambda.body);
33715
33912
  index = lambda.endTokenIndex;
33716
33913
  continue;
33717
33914
  }
33718
- const declaration = tryParseVariableDeclaration(tokens, index, lexed);
33915
+ const declaration = tryParseVariableDeclaration(
33916
+ tokens,
33917
+ index,
33918
+ lexed,
33919
+ braceScope
33920
+ );
33719
33921
  if (!declaration) continue;
33720
33922
  locals.push(declaration.local);
33721
33923
  if (declaration.missingInitializer) {
@@ -33731,36 +33933,14 @@ function indexLocals(tokens, pairs, lexed, diagnostics) {
33731
33933
  }
33732
33934
  return locals;
33733
33935
  }
33734
- function tryParseVariableDeclaration(tokens, start, lexed) {
33936
+ function tryParseVariableDeclaration(tokens, start, lexed, braceScope) {
33735
33937
  const first = tokens[start];
33736
33938
  if (!first || first.kind !== "type" && first.kind !== "identifier")
33737
33939
  return null;
33738
33940
  const inferred = first.kind === "identifier" && first.text === NEOSCRIPT_INFERRED_LOCAL_KEYWORD;
33739
- let cursor = start + 1;
33740
- if (!inferred && (first.text === "Dictionary" || first.text === "Set")) {
33741
- const open = tokens[cursor];
33742
- if (!open || open.kind !== "operator" || open.text !== "<") return null;
33743
- let angleDepth = 0;
33744
- while (cursor < tokens.length) {
33745
- const token = tokens[cursor];
33746
- if (!token) return null;
33747
- if (token.kind === "operator" && token.text === "<") angleDepth++;
33748
- if (token.kind === "operator" && token.text === ">") {
33749
- angleDepth--;
33750
- if (angleDepth === 0) {
33751
- cursor++;
33752
- break;
33753
- }
33754
- }
33755
- cursor++;
33756
- }
33757
- }
33758
- while (!inferred && tokens[cursor]?.kind === "punctuation" && tokens[cursor]?.text === "[" && tokens[cursor + 1]?.kind === "punctuation" && tokens[cursor + 1]?.text === "]") {
33759
- cursor += 2;
33760
- }
33761
- if (!inferred && tokens[cursor]?.kind === "operator" && tokens[cursor]?.text === "?") {
33762
- cursor++;
33763
- }
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;
33764
33944
  const name = tokens[cursor];
33765
33945
  const equals = tokens[cursor + 1];
33766
33946
  if (!name || name.kind !== "identifier") return null;
@@ -33772,7 +33952,7 @@ function tryParseVariableDeclaration(tokens, start, lexed) {
33772
33952
  const statementEnd = statementEndTokenIndex(tokens, cursor + 2);
33773
33953
  const initializerTokens = hasEquals ? tokens.slice(cursor + 2, statementEnd) : [];
33774
33954
  const terminator = tokens[statementEnd];
33775
- const scope = containingBraceRange(tokens, start, lexed.end);
33955
+ const scope = braceScope(start);
33776
33956
  return {
33777
33957
  local: {
33778
33958
  name: name.text,
@@ -33790,6 +33970,24 @@ function tryParseVariableDeclaration(tokens, start, lexed) {
33790
33970
  missingInitializer: inferred && (!hasEquals || initializerTokens.length === 0)
33791
33971
  };
33792
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
+ }
33793
33991
  function statementEndTokenIndex(tokens, start) {
33794
33992
  let depth = 0;
33795
33993
  for (let cursor = start; cursor < tokens.length; cursor++) {
@@ -33816,6 +34014,7 @@ function tryParseLambdaParameters(tokens, start, pairs, lexed) {
33816
34014
  if (!arrow2 || arrow2.kind !== "operator" || arrow2.text !== "=>") {
33817
34015
  return null;
33818
34016
  }
34017
+ const body2 = lambdaBodySpan(tokens, start + 1, pairs, lexed);
33819
34018
  return {
33820
34019
  locals: [
33821
34020
  {
@@ -33824,17 +34023,13 @@ function tryParseLambdaParameters(tokens, start, pairs, lexed) {
33824
34023
  typeTokens: [],
33825
34024
  inferred: false,
33826
34025
  declarationRange: open.range,
33827
- scopeStart: arrow2.end,
33828
- scopeEnd: lambdaExpressionScopeEnd(
33829
- tokens,
33830
- start + 2,
33831
- pairs,
33832
- lexed.end
33833
- ),
34026
+ scopeStart: body2.start,
34027
+ scopeEnd: body2.end,
33834
34028
  lambdaParameter: true,
33835
34029
  lambdaParameterIndex: 0
33836
34030
  }
33837
34031
  ],
34032
+ body: body2,
33838
34033
  endTokenIndex: start + 1
33839
34034
  };
33840
34035
  }
@@ -33842,12 +34037,8 @@ function tryParseLambdaParameters(tokens, start, pairs, lexed) {
33842
34037
  const closeIndex = pairs.get(start);
33843
34038
  if (closeIndex === void 0) return null;
33844
34039
  const arrow = tokens[closeIndex + 1];
33845
- const bodyOpen = tokens[closeIndex + 2];
33846
34040
  if (!arrow || arrow.kind !== "operator" || arrow.text !== "=>") return null;
33847
- const hasBlockBody = bodyOpen?.kind === "punctuation" && bodyOpen.text === "{";
33848
- const bodyCloseIndex = hasBlockBody ? pairs.get(closeIndex + 2) : void 0;
33849
- const bodyClose = bodyCloseIndex === void 0 ? void 0 : tokens[bodyCloseIndex];
33850
- const scopeEnd = hasBlockBody ? bodyClose?.start ?? lexed.end : lambdaExpressionScopeEnd(tokens, closeIndex + 2, pairs, lexed.end);
34041
+ const body = lambdaBodySpan(tokens, closeIndex + 1, pairs, lexed);
33851
34042
  const locals = [];
33852
34043
  let segmentStart = start + 1;
33853
34044
  for (let cursor = start + 1; cursor <= closeIndex; cursor++) {
@@ -33868,15 +34059,28 @@ function tryParseLambdaParameters(tokens, start, pairs, lexed) {
33868
34059
  segment[0]?.start ?? nameToken.start,
33869
34060
  nameToken.end
33870
34061
  ),
33871
- scopeStart: hasBlockBody && bodyOpen ? bodyOpen.end : bodyOpen?.start ?? arrow.end,
33872
- scopeEnd,
34062
+ scopeStart: body.start,
34063
+ scopeEnd: body.end,
33873
34064
  lambdaParameter: true,
33874
34065
  lambdaParameterIndex: locals.length
33875
34066
  });
33876
34067
  }
33877
34068
  segmentStart = cursor + 1;
33878
34069
  }
33879
- 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
+ };
33880
34084
  }
33881
34085
  function lambdaExpressionScopeEnd(tokens, bodyStart, pairs, sourceEnd) {
33882
34086
  for (let cursor = bodyStart; cursor < tokens.length; cursor++) {
@@ -33893,6 +34097,9 @@ function lambdaExpressionScopeEnd(tokens, bodyStart, pairs, sourceEnd) {
33893
34097
  }
33894
34098
  return sourceEnd;
33895
34099
  }
34100
+ function isCallTypeArgumentToken(token) {
34101
+ return token.kind === "identifier" || token.kind === "type" || [".", ",", "?", "[", "]"].includes(token.text);
34102
+ }
33896
34103
  function callOpenParenIndex(tokens, nameIndex) {
33897
34104
  if (tokens[nameIndex + 1]?.text === "(") return nameIndex + 1;
33898
34105
  if (tokens[nameIndex + 1]?.text !== "<") return -1;
@@ -33901,8 +34108,7 @@ function callOpenParenIndex(tokens, nameIndex) {
33901
34108
  const token = tokens[cursor];
33902
34109
  if (token.text === "<") depth++;
33903
34110
  else if (/^>+$/.test(token.text)) depth -= token.text.length;
33904
- else if (token.kind !== "identifier" && token.kind !== "type" && ![".", ",", "?", "[", "]"].includes(token.text))
33905
- return -1;
34111
+ else if (!isCallTypeArgumentToken(token)) return -1;
33906
34112
  if (depth === 0) return tokens[cursor + 1]?.text === "(" ? cursor + 1 : -1;
33907
34113
  if (depth < 0) return -1;
33908
34114
  }
@@ -33924,15 +34130,84 @@ function callTypeArgumentTokens(tokens, nameIndex, openIndex) {
33924
34130
  }
33925
34131
  return argumentsTokens;
33926
34132
  }
33927
- 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) {
33928
34166
  const references = [];
34167
+ const enclosing = enclosingOpenerIndex(tokens);
34168
+ const initializerBraces = /* @__PURE__ */ new Set();
34169
+ const patternBindings = /* @__PURE__ */ new Set();
33929
34170
  for (let index = 0; index < tokens.length; index++) {
33930
34171
  const token = tokens[index];
33931
- 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
+ }
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
+ }
33932
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
+ }
33933
34209
  const declarationKey = `${token.range.start.line}:${token.range.start.character}`;
33934
34210
  if (contextualKeywords.has(declarationKey)) continue;
33935
- const previous = tokens[index - 1];
33936
34211
  references.push({
33937
34212
  name: token.text,
33938
34213
  range: token.range,
@@ -33940,7 +34215,7 @@ function indexReferences(tokens, declarations, contextualKeywords) {
33940
34215
  end: token.end,
33941
34216
  member: previous?.kind === "punctuation" && previous.text === "." || previous?.kind === "operator" && previous.text === "?.",
33942
34217
  call: callOpenParenIndex(tokens, index) >= 0,
33943
- declaration: declarations.has(declarationKey)
34218
+ declaration: declarations.has(declarationKey) || patternBindings.has(index)
33944
34219
  });
33945
34220
  }
33946
34221
  return references;
@@ -33953,12 +34228,18 @@ function indexCalls(tokens, pairs, lexed) {
33953
34228
  const open = tokens[openIndex];
33954
34229
  if (!name || name.kind !== "identifier") continue;
33955
34230
  if (!open || open.kind !== "punctuation" || open.text !== "(") continue;
33956
- const contextualKeyword = tokens[index - 1];
33957
- 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;
33958
34237
  const closeIndex = pairs.get(openIndex);
33959
34238
  const close = closeIndex === void 0 ? void 0 : tokens[closeIndex];
33960
34239
  const ranges = [];
34240
+ const names = [];
33961
34241
  let segmentStart = open.end;
34242
+ let segmentStartIndex = openIndex + 1;
33962
34243
  let nested = 0;
33963
34244
  const limit = closeIndex ?? tokens.length;
33964
34245
  for (let cursor = openIndex + 1; cursor < limit; cursor++) {
@@ -33970,17 +34251,21 @@ function indexCalls(tokens, pairs, lexed) {
33970
34251
  nested--;
33971
34252
  if (nested === 0 && token.kind === "punctuation" && token.text === ",") {
33972
34253
  ranges.push(lexed.source.range(segmentStart, token.start));
34254
+ names.push(callArgumentLabel(tokens, segmentStartIndex, cursor));
33973
34255
  segmentStart = token.end;
34256
+ segmentStartIndex = cursor + 1;
33974
34257
  }
33975
34258
  }
33976
34259
  if (segmentStart < (close?.start ?? lexed.end)) {
33977
34260
  ranges.push(lexed.source.range(segmentStart, close?.start ?? lexed.end));
34261
+ names.push(callArgumentLabel(tokens, segmentStartIndex, limit));
33978
34262
  }
33979
34263
  calls.push({
33980
- kind: constructor ? "constructor" : "function",
34264
+ kind: contextualKeyword ? "constructor" : "function",
33981
34265
  name: name.text,
33982
34266
  nameRange: name.range,
33983
- ...constructor ? { contextualKeywordRange: contextualKeyword.range } : {},
34267
+ ...contextualKeyword ? { contextualKeywordRange: contextualKeyword.range } : {},
34268
+ ...targetTyped ? { targetTyped: true } : {},
33984
34269
  ...openIndex > index + 1 ? {
33985
34270
  typeArgumentTokens: callTypeArgumentTokens(
33986
34271
  tokens,
@@ -33990,11 +34275,17 @@ function indexCalls(tokens, pairs, lexed) {
33990
34275
  } : {},
33991
34276
  openParenOffset: open.start,
33992
34277
  ...close ? { closeParenOffset: close.end } : {},
33993
- argumentRanges: ranges
34278
+ argumentRanges: ranges,
34279
+ argumentNames: names
33994
34280
  });
33995
34281
  }
33996
34282
  return calls;
33997
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
+ }
33998
34289
  function validateTerminatedStatements(tokens, diagnostics) {
33999
34290
  for (let index = 0; index < tokens.length; index++) {
34000
34291
  const token = tokens[index];
@@ -34039,36 +34330,44 @@ function validateTerminatedStatements(tokens, diagnostics) {
34039
34330
  }
34040
34331
  }
34041
34332
  }
34042
- function containingBraceRange(tokens, tokenIndex, documentEnd) {
34043
- let depth = 0;
34044
- let start = 0;
34045
- 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;
34046
34340
  const token = tokens[index];
34047
- if (!token || token.kind !== "punctuation") continue;
34048
- if (token.text === "}") depth++;
34049
- if (token.text === "{") {
34050
- if (depth === 0) {
34051
- start = token.end;
34052
- break;
34053
- }
34054
- 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
+ };
34055
34357
  }
34056
- }
34057
- depth = 0;
34058
- let end = documentEnd;
34059
- for (let index = tokenIndex + 1; index < tokens.length; index++) {
34060
- const token = tokens[index];
34061
- if (!token || token.kind !== "punctuation") continue;
34062
- if (token.text === "{") depth++;
34063
- if (token.text === "}") {
34064
- if (depth === 0) {
34065
- end = token.start;
34066
- break;
34067
- }
34068
- 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;
34069
34364
  }
34070
- }
34071
- return { start, end };
34365
+ const close = unmatchedCloses[low];
34366
+ return {
34367
+ start: 0,
34368
+ end: close === void 0 ? documentEnd : tokens[close].start
34369
+ };
34370
+ };
34072
34371
  }
34073
34372
  function tryParseCatchParameter(tokens, start, pairs, lexed) {
34074
34373
  const keyword = tokens[start];
@@ -34116,7 +34415,7 @@ function tryParseCatchParameter(tokens, start, pairs, lexed) {
34116
34415
  resumeTokenIndex: closeIndex
34117
34416
  };
34118
34417
  }
34119
- function tryParseLoopLocal(tokens, start, pairs, lexed, diagnostics) {
34418
+ function tryParseLoopLocal(tokens, start, pairs, lexed, diagnostics, braceScope) {
34120
34419
  const keyword = tokens[start];
34121
34420
  if (!keyword || keyword.kind !== "keyword" || keyword.text !== "for" && keyword.text !== "foreach") {
34122
34421
  return null;
@@ -34127,7 +34426,12 @@ function tryParseLoopLocal(tokens, start, pairs, lexed, diagnostics) {
34127
34426
  if (closeIndex === void 0) return null;
34128
34427
  const scopeEnd = loopBodyScopeEnd(tokens, closeIndex + 1, pairs, lexed.end);
34129
34428
  if (keyword.text === "for") {
34130
- const declaration = tryParseVariableDeclaration(tokens, start + 2, lexed);
34429
+ const declaration = tryParseVariableDeclaration(
34430
+ tokens,
34431
+ start + 2,
34432
+ lexed,
34433
+ braceScope
34434
+ );
34131
34435
  if (!declaration || declaration.endTokenIndex >= closeIndex) return null;
34132
34436
  if (declaration.missingInitializer) {
34133
34437
  diagnostics.push({
@@ -34449,6 +34753,23 @@ var COLLECTION_QUERY_METHODS = {
34449
34753
  Reverse: "none",
34450
34754
  Concat: "collection"
34451
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
+ }
34452
34773
  function isCollectionQueryName(name) {
34453
34774
  return Object.hasOwn(COLLECTION_QUERY_METHODS, name);
34454
34775
  }
@@ -36339,10 +36660,12 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
36339
36660
  statement.pos
36340
36661
  );
36341
36662
  }
36342
- if (statement.target.kind === "member" && statement.target.name === "OnChanged") {
36663
+ if (statement.target.kind === "member" && statement.target.name === NEOSCRIPT_ON_CHANGED_MEMBER) {
36343
36664
  const observed = this.resolveExpression(statement.target.receiver, scope);
36344
36665
  const observedType = neoScriptMemberLookupType(observed.type);
36345
- 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
+ );
36346
36669
  if (!declared) {
36347
36670
  if (statement.op !== "+=" && statement.op !== "-=")
36348
36671
  throw new CompileError(ON_CHANGED_OPERATIONS_ERROR, statement.pos);
@@ -36561,12 +36884,12 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
36561
36884
  }
36562
36885
  /** `X.M.OnChanged.Clear()` empties M's listener set on X (P70, P106). */
36563
36886
  resolveChangeListenerClear(expression, scope, pos) {
36564
- 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)
36565
36888
  return null;
36566
36889
  const onChanged = expression.callee.receiver;
36567
36890
  const observed = this.resolveExpression(onChanged.receiver, scope);
36568
36891
  const observedType = neoScriptMemberLookupType(observed.type);
36569
- 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))
36570
36893
  return null;
36571
36894
  if (expression.callee.optional)
36572
36895
  throw new CompileError(
@@ -37292,7 +37615,14 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
37292
37615
  );
37293
37616
  }
37294
37617
  case "new": {
37295
- 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);
37296
37626
  if (vector3 !== null) {
37297
37627
  return this.resolveVectorConstructor(
37298
37628
  vector3,
@@ -37802,10 +38132,19 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
37802
38132
  };
37803
38133
  }
37804
38134
  resolveListLiteral(elements, scope, expected, pos) {
37805
- const expectedEntry = expected?.kind === "list" ? expected.elementType : void 0;
38135
+ const expectedEntry = expected?.kind === "list" || expected?.kind === "set" ? expected.elementType : void 0;
37806
38136
  const resolved = elements.map(
37807
38137
  (element) => this.resolveExpression(element, scope, expectedEntry)
37808
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
+ }
37809
38148
  let entryType = expectedEntry ?? resolved[0]?.type;
37810
38149
  if (!entryType) {
37811
38150
  throw new CompileError(
@@ -37827,6 +38166,14 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
37827
38166
  }
37828
38167
  entryType = common;
37829
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
+ }
37830
38177
  const type = {
37831
38178
  kind: "list",
37832
38179
  elementType: entryType
@@ -38763,7 +39110,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
38763
39110
  pos
38764
39111
  );
38765
39112
  }
38766
- if (name === "Id" && type.kind === "class") {
39113
+ if (name === NEOSCRIPT_CLASS_ID_MEMBER && type.kind === "class") {
38767
39114
  return this.keyOf(
38768
39115
  receiver,
38769
39116
  name,
@@ -38852,7 +39199,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
38852
39199
  entryUserData
38853
39200
  };
38854
39201
  }
38855
- if (name === "OnChanged")
39202
+ if (name === NEOSCRIPT_ON_CHANGED_MEMBER)
38856
39203
  throw new CompileError(ON_CHANGED_OPERATIONS_ERROR, pos);
38857
39204
  throw new CompileError(
38858
39205
  `Cannot read member '${name}' on ${this.describe(receiver.type)}`,
@@ -40349,23 +40696,12 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
40349
40696
  this.project.typeByName.get(className) ?? { declaredConstructors: [] }
40350
40697
  );
40351
40698
  }
40352
- const inferredTypes = this.inferOverloadArgumentTypes(
40699
+ const resolution = this.declaredConstructorResolution(
40353
40700
  declared,
40354
40701
  named,
40355
- expression,
40702
+ expression.args,
40356
40703
  scope
40357
40704
  );
40358
- const resolution = resolveNeoScriptDeclaredConstructorOverload(
40359
- declared,
40360
- named.map((name, index) => {
40361
- const inferred = inferredTypes?.[index];
40362
- if (!inferred) return { name };
40363
- return {
40364
- name,
40365
- matchesParameter: (parameter3) => isNeoScriptTypeAssignable(inferred, parameter3.type, this.project)
40366
- };
40367
- })
40368
- );
40369
40705
  if (resolution.kind === "resolved") return resolution.constructor;
40370
40706
  if (resolution.kind === "ambiguous") {
40371
40707
  throw new CompileError(
@@ -40378,6 +40714,38 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
40378
40714
  pos
40379
40715
  );
40380
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
+ }
40381
40749
  /**
40382
40750
  * Types for the §6.1.1 step-2 tie-break, computed only when several
40383
40751
  * overloads share the call's name set. Expected-type inference is
@@ -40385,7 +40753,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
40385
40753
  * known — so an argument that needs it (a contextual enum option, a
40386
40754
  * target-typed `new`) simply does not participate in the tie-break.
40387
40755
  */
40388
- inferOverloadArgumentTypes(declared, named, expression, scope) {
40756
+ inferOverloadArgumentTypes(declared, named, args, scope) {
40389
40757
  const nameSetKey = neoScriptArgumentNameSetKey(named);
40390
40758
  const sharing = declared.filter(
40391
40759
  (candidate) => neoScriptArgumentNameSetKey(
@@ -40394,7 +40762,7 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
40394
40762
  );
40395
40763
  if (sharing.length < 2) return null;
40396
40764
  return named.map((_, index) => {
40397
- const argument2 = expression.args[index];
40765
+ const argument2 = args[index];
40398
40766
  if (!argument2) return null;
40399
40767
  try {
40400
40768
  return this.resolveExpression(argument2, scope).type;
@@ -41078,6 +41446,15 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41078
41446
  resolveCollectionFunction(receiver, name, args, scope, pos) {
41079
41447
  const collection = collectionPartsFor(receiver);
41080
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
+ }
41081
41458
  if (isCollectionQueryName(name)) {
41082
41459
  return this.resolveCollectionQuery(
41083
41460
  receiver,
@@ -41089,12 +41466,6 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41089
41466
  );
41090
41467
  }
41091
41468
  if (name === "Count") {
41092
- if (args.length > 1) {
41093
- throw new CompileError(
41094
- `Count expects zero or one predicate, got ${args.length}.`,
41095
- pos
41096
- );
41097
- }
41098
41469
  const fn = args[0] ? this.resolveCollectionLambda(
41099
41470
  args[0],
41100
41471
  collection,
@@ -41170,7 +41541,6 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41170
41541
  );
41171
41542
  }
41172
41543
  if (name === "Where") {
41173
- requireArgCount(name, args, 1, pos);
41174
41544
  const fn = this.resolveCollectionLambda(
41175
41545
  requiredAt(args, 0),
41176
41546
  collection,
@@ -41193,12 +41563,6 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41193
41563
  };
41194
41564
  }
41195
41565
  if (name === "First" || name === "FirstOrDefault" || name === "Find") {
41196
- if (args.length > 1) {
41197
- throw new CompileError(
41198
- `${name} expects zero or one predicate, got ${args.length}.`,
41199
- pos
41200
- );
41201
- }
41202
41566
  const fn = args[0] ? this.resolveCollectionLambda(
41203
41567
  args[0],
41204
41568
  collection,
@@ -41223,7 +41587,6 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41223
41587
  };
41224
41588
  }
41225
41589
  if (name === "Select") {
41226
- requireArgCount(name, args, 1, pos);
41227
41590
  const lambda = requiredAt(args, 0);
41228
41591
  if (lambda.kind !== "lambda") {
41229
41592
  throw new CompileError("Select requires a lambda argument.", pos);
@@ -41250,16 +41613,6 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41250
41613
  return null;
41251
41614
  }
41252
41615
  resolveCollectionQuery(receiver, collection, name, args, scope, pos) {
41253
- const kind = COLLECTION_QUERY_METHODS[name];
41254
- if (kind === "optionalPredicate") {
41255
- if (args.length > 1)
41256
- throw new CompileError(
41257
- `${name} expects zero or one predicate, got ${args.length}.`,
41258
- pos
41259
- );
41260
- } else {
41261
- requireArgCount(name, args, kind === "none" ? 0 : 1, pos);
41262
- }
41263
41616
  const base = { collectionPointer: receiver.pointer };
41264
41617
  let info;
41265
41618
  let resultType = {
@@ -41425,6 +41778,8 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
41425
41778
  };
41426
41779
  }
41427
41780
  resolveScalarFunction(receiver, name, args, scope, pos) {
41781
+ if (receiver.type.kind !== "primitive" || !neoScriptScalarMethod(receiver.type.name, name))
41782
+ return null;
41428
41783
  if (isPrimitive(receiver.type, "string")) {
41429
41784
  if (name === "Contains") {
41430
41785
  requireArgCount("string.Contains", args, 1, pos);
@@ -42576,27 +42931,26 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
42576
42931
  };
42577
42932
  }
42578
42933
  /**
42579
- * The vector leaf a target-typed `new(…)` constructs, or null when the
42580
- * 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.
42581
42936
  *
42582
42937
  * A vector has fields rather than members, so neither of `new`'s two
42583
42938
  * declaration-side spellings applies to it: an argument names a component by
42584
42939
  * position and there is no member for an initializer block to settle.
42585
42940
  */
42586
- targetTypedVectorKind(expression, expected) {
42587
- if (expression.className !== null) return null;
42588
- if (expected?.kind !== "primitive") return null;
42589
- const vector3 = vectorKind(expected.name);
42941
+ constructedVectorKind(expression, constructed) {
42942
+ const vector3 = constructed === null ? null : vectorKind(constructed);
42590
42943
  if (vector3 === null) return null;
42944
+ const spelling = expression.className === null ? "new(\u2026)" : `new ${vector3}(\u2026)`;
42591
42945
  if (expression.argumentNames !== void 0) {
42592
42946
  throw new CompileError(
42593
- `${vector3} components are positional, so \`new(\u2026)\` cannot name them.`,
42947
+ `${vector3} components are positional, so \`${spelling}\` cannot name them.`,
42594
42948
  expression.pos
42595
42949
  );
42596
42950
  }
42597
42951
  if ((expression.initializer?.length ?? 0) > 0) {
42598
42952
  throw new CompileError(
42599
- `${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.`,
42600
42954
  expression.pos
42601
42955
  );
42602
42956
  }
@@ -42767,6 +43121,12 @@ var StrictNeoScriptResolver = class _StrictNeoScriptResolver {
42767
43121
  }
42768
43122
  requireAssignable(source, target, pos, usage) {
42769
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
+ }
42770
43130
  const prefix = usage === "return" ? "Returned" : "Cannot use";
42771
43131
  throw new CompileError(
42772
43132
  `${prefix} ${this.describe(source)} ${usage === "return" ? "is not assignable to declared return type" : `as ${usage} of type`} ${this.describe(target)}`,
@@ -44041,17 +44401,6 @@ function collectionOperationValueType(expression, collection) {
44041
44401
  function isLookupSelectionCollection(expression, collection) {
44042
44402
  return collection.kind === "set" && expression.wireType?.type === 9 /* Lookup */;
44043
44403
  }
44044
- var SPRITE_DERIVED_MEMBERS = {
44045
- FileName: { kind: "primitive", name: "string" },
44046
- Name: { kind: "primitive", name: "string" },
44047
- Size: { kind: "primitive", name: "Vector2" },
44048
- Pivot: { kind: "primitive", name: "Vector2" },
44049
- Slices: {
44050
- kind: "list",
44051
- elementType: { kind: "primitive", name: "SpriteInfo" },
44052
- readOnly: true
44053
- }
44054
- };
44055
44404
  function assignableFieldList(owner) {
44056
44405
  if (!isNeoScriptStructuredLeafTypeName(owner)) return "a stored field";
44057
44406
  const names = neoScriptStructuredLeafFieldNames(owner);
@@ -44065,19 +44414,8 @@ function resolvePrimitiveMember(type, name) {
44065
44414
  );
44066
44415
  if (field) return { type: field.type, key: field.key };
44067
44416
  }
44068
- if (type.name === "SpriteInfo" && Object.prototype.hasOwnProperty.call(SPRITE_DERIVED_MEMBERS, name)) {
44069
- const derived = SPRITE_DERIVED_MEMBERS[name];
44070
- if (derived) return { type: derived, derived: true };
44071
- }
44072
- if (type.name === "AudioClipInfo") {
44073
- if (name === "url" || name === "name")
44074
- return { type: { kind: "primitive", name: "string" } };
44075
- if (name === "length")
44076
- return { type: { kind: "primitive", name: "float" } };
44077
- }
44078
- if (type.name === "NeoDialogueReference" && name === "id")
44079
- return { type: { kind: "primitive", name: "string" } };
44080
- return null;
44417
+ const derived = neoScriptPrimitiveDerivedMember(type.name, name);
44418
+ return derived ? { type: derived.type, derived: true } : null;
44081
44419
  }
44082
44420
  function isActionMemberPointer(pointer) {
44083
44421
  if (pointer.type === "staticMember" /* StaticMember */) return true;
@@ -44326,6 +44664,17 @@ function functionArityMessage(name, minimum, maximum, got) {
44326
44664
  }
44327
44665
  return `Function '${name}' expects between ${minimum} and ${maximum} arguments, got ${got}.`;
44328
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
+ }
44329
44678
  function requireArgCount(name, args, expected, pos) {
44330
44679
  if (args.length === expected) return;
44331
44680
  throw new CompileError(
@@ -44407,6 +44756,18 @@ function resolveNeoScriptType(type, context, project) {
44407
44756
  resolved = registryReference;
44408
44757
  break;
44409
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
+ }
44410
44771
  const named = project.typeByName.get(type.name);
44411
44772
  if (!named)
44412
44773
  throw new CompileError(
@@ -46031,7 +46392,7 @@ function manifestParameterDefault(argument2, environment, field) {
46031
46392
  const value = constantDefaultValue(declared.value, `${field}.default.value`);
46032
46393
  const type = record2(argument2.type, `${field}.type`);
46033
46394
  const kind = string(type.kind, `${field}.type.kind`);
46034
- const enumOptionName = kind === "enum" && typeof value === "string" ? manifestEnumOptionName(
46395
+ const enumOptionName2 = kind === "enum" && typeof value === "string" ? manifestEnumOptionName(
46035
46396
  string(type.enumId, `${field}.type.enumId`),
46036
46397
  value,
46037
46398
  environment
@@ -46041,7 +46402,7 @@ function manifestParameterDefault(argument2, environment, field) {
46041
46402
  displayText: neoScriptParameterDefaultDisplayText({
46042
46403
  value,
46043
46404
  kind: kind === "enum" || kind === "decimal" ? kind : "other",
46044
- ...enumOptionName === void 0 ? {} : { enumOptionName }
46405
+ ...enumOptionName2 === void 0 ? {} : { enumOptionName: enumOptionName2 }
46045
46406
  }),
46046
46407
  value
46047
46408
  }
@@ -46906,13 +47267,13 @@ function overrideBaseClass(context) {
46906
47267
  function parameterDefaultDescriptor(argument2, context) {
46907
47268
  if (argument2.defaultValue === void 0) return {};
46908
47269
  const value = argument2.defaultValue.value;
46909
- 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;
46910
47271
  return {
46911
47272
  defaultValue: {
46912
47273
  displayText: neoScriptParameterDefaultDisplayText({
46913
47274
  value,
46914
47275
  kind: parameterDefaultSpellingKind(argument2.type),
46915
- ...enumOptionName === void 0 ? {} : { enumOptionName }
47276
+ ...enumOptionName2 === void 0 ? {} : { enumOptionName: enumOptionName2 }
46916
47277
  }),
46917
47278
  value
46918
47279
  }
@@ -48535,8 +48896,9 @@ function createContext(ctx, options) {
48535
48896
  }
48536
48897
 
48537
48898
  // ../src/database/neoscript/compile-delegate-closure.ts
48899
+ var CLOSURE_GETTER_PREFIX = "return ";
48538
48900
  function compileDelegateClosureValue(code, signature) {
48539
- const compiled = compileNSGetter(`return ${code};`, {
48901
+ const compiled = compileNSGetter(`${CLOSURE_GETTER_PREFIX}${code};`, {
48540
48902
  project: signature.project,
48541
48903
  projectFiles: [...signature.projectFiles ?? []],
48542
48904
  dialogueGroups: signature.dialogueGroups ?? [],
@@ -48554,7 +48916,8 @@ function compileDelegateClosureValue(code, signature) {
48554
48916
  returnTypeInfo: signature.returnTypeInfo,
48555
48917
  argumentTypes: [...signature.argumentTypes]
48556
48918
  },
48557
- functionName: signature.name
48919
+ functionName: signature.name,
48920
+ compilationProject: signature.compilationProject
48558
48921
  });
48559
48922
  const instruction = compiled.instructions[0];
48560
48923
  if (compiled.instructions.length !== 1 || instruction?.type !== "return" /* return */ || instruction.pointer?.type !== "value" /* value */) {
@@ -48644,7 +49007,8 @@ function compileMemberInitializerBody(args) {
48644
49007
  error,
48645
49008
  memberId: args.member.id,
48646
49009
  memberName: args.member.name,
48647
- valueId: null
49010
+ valueId: null,
49011
+ code: defaultValue.init.code
48648
49012
  });
48649
49013
  }
48650
49014
  Object.assign(defaultValue.init, { compiled });
@@ -48703,7 +49067,8 @@ function compileValueRowInitializerBody(args) {
48703
49067
  error,
48704
49068
  memberId: args.member.id,
48705
49069
  memberName: args.member.name,
48706
- valueId: args.valueId
49070
+ valueId: args.valueId,
49071
+ code: container.init.code
48707
49072
  });
48708
49073
  }
48709
49074
  Object.assign(container.init, { compiled });
@@ -48732,10 +49097,20 @@ var NeoScriptBodyCompileError = class extends Error {
48732
49097
  memberId;
48733
49098
  memberName;
48734
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;
48735
49107
  bodyPosition;
49108
+ /** The compiler's message without its body position. */
49109
+ detail;
48736
49110
  constructor(args) {
48737
- const subject = args.valueId === null ? `Member "${args.memberName}" (${args.memberId})` : `Value row "${args.valueId}" of member "${args.memberName}" (${args.memberId})`;
48738
- 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}`;
48739
49114
  super(
48740
49115
  `${subject} has a NeoScript body that failed to compile${at2}: ${args.detail}`
48741
49116
  );
@@ -48743,18 +49118,24 @@ var NeoScriptBodyCompileError = class extends Error {
48743
49118
  this.memberId = args.memberId;
48744
49119
  this.memberName = args.memberName;
48745
49120
  this.valueId = args.valueId;
49121
+ this.argument = args.argument ?? null;
49122
+ this.code = args.code;
48746
49123
  this.bodyPosition = args.bodyPosition;
49124
+ this.detail = args.detail;
48747
49125
  }
48748
49126
  };
48749
49127
  function throwNamedBodyCompileFailure(args) {
48750
49128
  if (args.error instanceof NeoScriptBodyCompileError) throw args.error;
48751
49129
  const compileError = args.error instanceof CompileError ? args.error : null;
48752
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 };
48753
49132
  throw new NeoScriptBodyCompileError({
48754
49133
  memberId: args.memberId,
48755
49134
  memberName: args.memberName,
48756
49135
  valueId: args.valueId,
48757
- 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,
48758
49139
  detail: compileError === null ? detail : detail.replace(
48759
49140
  new RegExp(`^${compileError.line}:${compileError.column}: `),
48760
49141
  ""
@@ -56025,79 +56406,9 @@ var INITIALIZER_KEY_PLACEHOLDER = new RegExp(
56025
56406
  "g"
56026
56407
  );
56027
56408
 
56028
- // ../packages/neoscript-language/src/project-schema-contract.generated.ts
56029
- var PROJECT_FILE_UPLOAD_BATCH_SIZE = 32;
56030
-
56031
- // src/project-source/lower-configuration.ts
56032
- var wireEnumOptions = () => (options) => options;
56033
- var TEXTURE_TYPE_WIRE_OPTIONS = wireEnumOptions()([
56034
- "default",
56035
- "normal-map",
56036
- "editor-gui-and-legacy-gui",
56037
- "sprite",
56038
- "cursor",
56039
- "cookie",
56040
- "lightmap",
56041
- "single-channel"
56042
- ]);
56043
- var ALPHA_SOURCE_WIRE_OPTIONS = wireEnumOptions()(["none", "input-texture-alpha", "from-gray-scale"]);
56044
- var NON_POWER_OF_TWO_SCALE_WIRE_OPTIONS = wireEnumOptions()(["none", "to-nearest", "to-larger", "to-smaller"]);
56045
- var MIP_MAP_FILTERING_WIRE_OPTIONS = wireEnumOptions()(["box", "kaiser"]);
56046
- var WRAP_MODE_WIRE_OPTIONS = wireEnumOptions()(["repeat", "clamp", "mirror", "mirror-once", "per-axis"]);
56047
- var FILTER_MODE_WIRE_OPTIONS = wireEnumOptions()(["point", "bilinear", "trilinear"]);
56048
- var RESIZE_ALGORITHM_WIRE_OPTIONS = wireEnumOptions()(["mitchell", "bilinear"]);
56049
- var TEXTURE_COMPRESSION_WIRE_OPTIONS = wireEnumOptions()(["none", "low-quality", "normal-quality", "high-quality"]);
56050
- var PLATFORM_FORMAT_WIRE_OPTIONS = wireEnumOptions()([
56051
- "automatic",
56052
- "rgba-compressed-dxt5-bc3",
56053
- "rgb-compressed-dxt1-bc1",
56054
- "rgba-32-bit",
56055
- "rgb-24-bit"
56056
- ]);
56057
- var SPRITE_MODE_WIRE_OPTIONS = wireEnumOptions()(["single", "multiple", "polygon"]);
56058
- var MESH_TYPE_WIRE_OPTIONS = wireEnumOptions()(["full-rect", "tight"]);
56059
- var PIVOT_ALIGNMENT_WIRE_OPTIONS = wireEnumOptions()([
56060
- "center",
56061
- "top-left",
56062
- "top-center",
56063
- "top-right",
56064
- "left-center",
56065
- "right-center",
56066
- "bottom-left",
56067
- "bottom-center",
56068
- "bottom-right",
56069
- "custom"
56070
- ]);
56071
- var SLICE_TYPE_WIRE_OPTIONS = wireEnumOptions()(["grid-by-cell-size"]);
56072
- var SLICE_NAMING_ORDER_WIRE_OPTIONS = wireEnumOptions()(["row-major", "column-major"]);
56073
- var NORMAL_MAP_FILTERING_WIRE_OPTIONS = wireEnumOptions()(["sharp", "smooth"]);
56074
- var COOKIE_LIGHT_TYPE_WIRE_OPTIONS = wireEnumOptions()(["spot", "directional", "point"]);
56075
- var SINGLE_CHANNEL_COMPONENT_WIRE_OPTIONS = wireEnumOptions()(["alpha", "red"]);
56076
- var SWIZZLE_WIRE_OPTIONS = wireEnumOptions()(["red", "green", "blue", "alpha", "zero", "one"]);
56077
- var AUDIO_LOAD_TYPE_WIRE_OPTIONS = wireEnumOptions()(["decompress-on-load", "compressed-in-memory", "streaming"]);
56078
- var AUDIO_COMPRESSION_FORMAT_WIRE_OPTIONS = wireEnumOptions()(["pcm", "adpcm", "vorbis"]);
56079
- var AUDIO_SAMPLE_RATE_WIRE_OPTIONS = wireEnumOptions()(["preserve-sample-rate", "optimize-sample-rate", "override-sample-rate"]);
56080
-
56081
- // src/project-source/lower-relations.ts
56082
- var RELATION_KIND_BY_PROPERTY = /* @__PURE__ */ new Map([
56083
- ["tileImports", "world.grid.tile-import"],
56084
- ["objectImports", "world.grid.object-import"],
56085
- ["tileLayers", "world.grid.tile-layer"],
56086
- ["objectLayers", "world.grid.object-layer"]
56087
- ]);
56088
- var SPECIALIZED_RELATION_KINDS = /* @__PURE__ */ new Set([
56089
- ...RELATION_KIND_BY_PROPERTY.values(),
56090
- "world.tile.compatible-layer",
56091
- "world.tile.default-layer",
56092
- "world.object.compatible-layer",
56093
- "world.object.default-layer",
56094
- "world.tile-layer-link.target",
56095
- "world.object-layer-link.target"
56096
- ]);
56097
-
56098
56409
  // ../packages/manifest/schema-contract/registry.mjs
56099
56410
  var PROJECT_SCHEMA_CONTRACT = Object.freeze({
56100
- cliVersion: "0.76.1",
56411
+ cliVersion: "0.76.2",
56101
56412
  projectFileUploadBatchSize: 32,
56102
56413
  documentRecords: {
56103
56414
  member: {
@@ -57531,6 +57842,76 @@ var PROJECT_SCHEMA_CONTRACT = Object.freeze({
57531
57842
  }
57532
57843
  });
57533
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
+
57534
57915
  // src/project-source/workspace-status-core.ts
57535
57916
  var ANIMATION_DOCUMENT_RECORD_KINDS = [
57536
57917
  ProjectRecordKind.Project,