@neocompose/cli 0.27.1 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/neo.mjs CHANGED
@@ -1813,6 +1813,9 @@ var init_generated_csharp_identifiers = __esm({
1813
1813
  });
1814
1814
 
1815
1815
  // ../packages/neoscript-language/src/project.ts
1816
+ function neoScriptParameterIsOmittable(parameter4) {
1817
+ return parameter4.defaultValue !== void 0;
1818
+ }
1816
1819
  function neoScriptRequiredConstructor(type) {
1817
1820
  return type?.declaredConstructors?.find(
1818
1821
  (candidate) => candidate.required === true
@@ -1820,7 +1823,7 @@ function neoScriptRequiredConstructor(type) {
1820
1823
  }
1821
1824
  function neoScriptParameterlessConstructor(type) {
1822
1825
  return type.declaredConstructors?.find(
1823
- (candidate) => candidate.parameters.length === 0
1826
+ (candidate) => candidate.parameters.every(neoScriptParameterIsOmittable)
1824
1827
  ) ?? null;
1825
1828
  }
1826
1829
  function isNeoScriptConstructionDocumentKind(kind) {
@@ -2357,11 +2360,11 @@ function signatureHelp(snapshot, position) {
2357
2360
  return {
2358
2361
  signatures: declared.map((candidate) => ({
2359
2362
  label: `${type.name}(${candidate.parameters.map(
2360
- (parameter4) => `${formatType(parameter4.type, snapshot.project)} ${parameter4.name}`
2363
+ (parameter4) => `${formatType(parameter4.type, snapshot.project)} ${parameter4.name}${parameterDefaultSuffix(parameter4)}`
2361
2364
  ).join(", ")})`,
2362
2365
  ...candidate.documentation ? { documentation: candidate.documentation } : {},
2363
2366
  parameters: candidate.parameters.map((parameter4) => ({
2364
- label: `${formatType(parameter4.type, snapshot.project)} ${parameter4.name}`,
2367
+ label: `${formatType(parameter4.type, snapshot.project)} ${parameter4.name}${parameterDefaultSuffix(parameter4)}`,
2365
2368
  ...parameter4.documentation ? { documentation: parameter4.documentation } : {}
2366
2369
  }))
2367
2370
  })),
@@ -2404,7 +2407,7 @@ function signatureHelp(snapshot, position) {
2404
2407
  label: formatSymbolSignature(symbol, snapshot.project),
2405
2408
  ...symbol.documentation ? { documentation: symbol.documentation } : {},
2406
2409
  parameters: symbol.parameters.map((parameter4) => ({
2407
- label: `${formatType(parameter4.type, snapshot.project)} ${parameter4.name}`,
2410
+ label: `${formatType(parameter4.type, snapshot.project)} ${parameter4.name}${parameterDefaultSuffix(parameter4)}`,
2408
2411
  ...parameter4.documentation ? { documentation: parameter4.documentation } : {}
2409
2412
  }))
2410
2413
  }
@@ -4140,9 +4143,14 @@ function displaySymbolKind(symbol) {
4140
4143
  }
4141
4144
  return symbol.kind.charAt(0).toUpperCase() + symbol.kind.slice(1);
4142
4145
  }
4146
+ function parameterDefaultSuffix(parameter4) {
4147
+ return parameter4.defaultValue === void 0 ? "" : ` = ${parameter4.defaultValue.displayText}`;
4148
+ }
4143
4149
  function formatSymbolSignature(symbol, project) {
4144
4150
  if (symbol.parameters !== void 0) {
4145
- const parameters = symbol.parameters.map((item) => `${formatType(item.type, project)} ${item.name}`).join(", ");
4151
+ const parameters = symbol.parameters.map(
4152
+ (item) => `${formatType(item.type, project)} ${item.name}${parameterDefaultSuffix(item)}`
4153
+ ).join(", ");
4146
4154
  const returnType = symbol.returnType ?? symbol.type;
4147
4155
  const deferred = symbol.deferred ? "Task<" : "";
4148
4156
  const end = symbol.deferred ? ">" : "";
@@ -7323,11 +7331,24 @@ var init_strict_parser = __esm({
7323
7331
  function neoScriptArgumentNameSetKey(names) {
7324
7332
  return [...names].map((name) => name.toLowerCase()).sort().join(",");
7325
7333
  }
7326
- function parameterNameSetKey(parameters) {
7327
- return neoScriptArgumentNameSetKey(
7328
- parameters.map((parameter4) => parameter4.name)
7334
+ function neoScriptCallMatchesParameters(suppliedNames, parameters) {
7335
+ const supplied = new Set(suppliedNames.map((name) => name.toLowerCase()));
7336
+ const declared = new Set(
7337
+ parameters.map((parameter4) => parameter4.name.toLowerCase())
7338
+ );
7339
+ for (const name of supplied) {
7340
+ if (!declared.has(name)) return false;
7341
+ }
7342
+ return parameters.every(
7343
+ (parameter4) => parameter4.defaulted || supplied.has(parameter4.name.toLowerCase())
7329
7344
  );
7330
7345
  }
7346
+ function callableShape(parameters) {
7347
+ return parameters.map((parameter4) => ({
7348
+ name: parameter4.name,
7349
+ defaulted: neoScriptParameterIsOmittable(parameter4)
7350
+ }));
7351
+ }
7331
7352
  function neoScriptPositionalTypeKey(type) {
7332
7353
  switch (type.kind) {
7333
7354
  case "primitive":
@@ -7385,8 +7406,108 @@ function validateNeoScriptOverloadSignatures(className, signatures) {
7385
7406
  message: `Class '${className}' declares constructors (${parameterLists.join(") and (")}) that differ only by parameter name; generated C# would emit the same constructor signature twice.`
7386
7407
  });
7387
7408
  }
7409
+ errors.push(...defaultedTieErrors(className, signatures));
7410
+ errors.push(...effectiveArityCollisionErrors(className, signatures));
7411
+ return errors;
7412
+ }
7413
+ function defaultedTieErrors(className, signatures) {
7414
+ const errors = [];
7415
+ for (let first = 0; first < signatures.length; first += 1) {
7416
+ for (let second = first + 1; second < signatures.length; second += 1) {
7417
+ const left = signatures[first];
7418
+ const right = signatures[second];
7419
+ if (left === void 0 || right === void 0) continue;
7420
+ if (namedSignatureKey(left) === namedSignatureKey(right)) continue;
7421
+ if (left.parameters.length !== right.parameters.length) continue;
7422
+ const leftHasDefault = left.parameters.some(
7423
+ (parameter4) => parameter4.defaulted === true
7424
+ );
7425
+ const rightHasDefault = right.parameters.some(
7426
+ (parameter4) => parameter4.defaulted === true
7427
+ );
7428
+ if (!leftHasDefault && !rightHasDefault) continue;
7429
+ const tyingCall = tyingCallNames(left, right);
7430
+ if (tyingCall === null) continue;
7431
+ const callDescription = tyingCall.length === 0 ? "`new()`" : `\`new(${tyingCall.join(": \u2026, ")}: \u2026)\``;
7432
+ errors.push({
7433
+ kind: "duplicateNameSet",
7434
+ constructorIds: [left.id, right.id],
7435
+ message: `Class '${className}' declares constructors (${describeSignatureParameters(left)}) and (${describeSignatureParameters(right)}) that the call ${callDescription} would match with the same number of defaulted fill-ins and the same argument types; no call site could resolve between them.`
7436
+ });
7437
+ }
7438
+ }
7439
+ return errors;
7440
+ }
7441
+ function tyingCallNames(left, right) {
7442
+ const leftTypes = new Map(
7443
+ left.parameters.map((parameter4) => [
7444
+ parameter4.name.toLowerCase(),
7445
+ parameter4.typeKey
7446
+ ])
7447
+ );
7448
+ const rightTypes = new Map(
7449
+ right.parameters.map((parameter4) => [
7450
+ parameter4.name.toLowerCase(),
7451
+ parameter4.typeKey
7452
+ ])
7453
+ );
7454
+ const tying = /* @__PURE__ */ new Map();
7455
+ for (const parameter4 of [...left.parameters, ...right.parameters]) {
7456
+ if (parameter4.defaulted === true) continue;
7457
+ tying.set(parameter4.name.toLowerCase(), parameter4.name);
7458
+ }
7459
+ for (const name of tying.keys()) {
7460
+ const leftType = leftTypes.get(name);
7461
+ const rightType = rightTypes.get(name);
7462
+ if (leftType === void 0) return null;
7463
+ if (rightType === void 0) return null;
7464
+ if (leftType !== rightType) return null;
7465
+ }
7466
+ return [...tying.values()];
7467
+ }
7468
+ function effectiveArityCollisionErrors(className, signatures) {
7469
+ const errors = [];
7470
+ const byEffectiveKey = /* @__PURE__ */ new Map();
7471
+ for (const signature of signatures) {
7472
+ const minimumArity = signature.parameters.filter(
7473
+ (parameter4) => parameter4.defaulted !== true
7474
+ ).length;
7475
+ for (let arity = minimumArity; arity <= signature.parameters.length; arity += 1) {
7476
+ const key = signature.parameters.slice(0, arity).map((parameter4) => parameter4.typeKey).join(",");
7477
+ byEffectiveKey.set(key, [
7478
+ ...byEffectiveKey.get(key) ?? [],
7479
+ { signature, arity }
7480
+ ]);
7481
+ }
7482
+ }
7483
+ const reportedPairs = /* @__PURE__ */ new Set();
7484
+ for (const entries of byEffectiveKey.values()) {
7485
+ if (entries.length < 2) continue;
7486
+ const shortened = entries.some(
7487
+ (entry) => entry.arity < entry.signature.parameters.length
7488
+ );
7489
+ if (!shortened) continue;
7490
+ const ids = entries.map((entry) => entry.signature.id);
7491
+ const pairKey = [...ids].sort().join("|");
7492
+ if (reportedPairs.has(pairKey)) continue;
7493
+ reportedPairs.add(pairKey);
7494
+ const parameterLists = entries.map(
7495
+ (entry) => describeSignatureParameters(entry.signature)
7496
+ );
7497
+ errors.push({
7498
+ kind: "positionalCollision",
7499
+ constructorIds: ids,
7500
+ message: `Class '${className}' declares constructors (${parameterLists.join(") and (")}) that expose the same C# positional signature once defaulted parameters are omitted; C# would resolve the shared arity differently from NeoScript's named overloads.`
7501
+ });
7502
+ }
7388
7503
  return errors;
7389
7504
  }
7505
+ function describeSignatureParameters(signature) {
7506
+ return signature.parameters.map((parameter4) => {
7507
+ const defaulted = parameter4.defaulted === true ? " = \u2026" : "";
7508
+ return `${parameter4.name}${defaulted}`;
7509
+ }).join(", ");
7510
+ }
7390
7511
  function namedSignatureKey(signature) {
7391
7512
  return [...signature.parameters].map((parameter4) => `${parameter4.name.toLowerCase()}:${parameter4.typeKey}`).sort().join(",");
7392
7513
  }
@@ -7397,23 +7518,35 @@ function validateNeoScriptDeclaredConstructorOverloads(className, constructors)
7397
7518
  id: constructor2.id,
7398
7519
  parameters: constructor2.parameters.map((parameter4) => ({
7399
7520
  name: parameter4.name,
7400
- typeKey: neoScriptPositionalTypeKey(parameter4.type)
7521
+ typeKey: neoScriptPositionalTypeKey(parameter4.type),
7522
+ defaulted: parameter4.defaultValue !== void 0
7401
7523
  }))
7402
7524
  }))
7403
7525
  );
7404
7526
  }
7405
7527
  function resolveNeoScriptDeclaredConstructorOverload(constructors, args) {
7406
- const callKey = neoScriptArgumentNameSetKey(args.map((entry) => entry.name));
7407
- const byName = constructors.filter(
7408
- (constructor2) => parameterNameSetKey(constructor2.parameters) === callKey
7528
+ const suppliedNames = args.map((entry) => entry.name);
7529
+ const applicable = constructors.filter(
7530
+ (constructor2) => neoScriptCallMatchesParameters(
7531
+ suppliedNames,
7532
+ callableShape(constructor2.parameters)
7533
+ )
7534
+ );
7535
+ if (applicable.length === 0) return { kind: "noMatch" };
7536
+ const fewestFillIns = Math.min(
7537
+ ...applicable.map(
7538
+ (constructor2) => constructor2.parameters.length - args.length
7539
+ )
7409
7540
  );
7410
- if (byName.length === 0) return { kind: "noMatch" };
7411
- if (byName.length === 1) {
7412
- const only = byName[0];
7541
+ const best = applicable.filter(
7542
+ (constructor2) => constructor2.parameters.length - args.length === fewestFillIns
7543
+ );
7544
+ if (best.length === 1) {
7545
+ const only = best[0];
7413
7546
  if (!only) return { kind: "noMatch" };
7414
7547
  return { kind: "resolved", constructor: only };
7415
7548
  }
7416
- const byType = byName.filter(
7549
+ const byType = best.filter(
7417
7550
  (constructor2) => args.every((argument2) => {
7418
7551
  const parameter4 = constructor2.parameters.find(
7419
7552
  (candidate) => candidate.name.toLowerCase() === argument2.name.toLowerCase()
@@ -7428,17 +7561,23 @@ function resolveNeoScriptDeclaredConstructorOverload(constructors, args) {
7428
7561
  if (!only) return { kind: "noMatch" };
7429
7562
  return { kind: "resolved", constructor: only };
7430
7563
  }
7431
- if (byType.length === 0) return { kind: "ambiguous", candidates: byName };
7564
+ if (byType.length === 0) return { kind: "ambiguous", candidates: best };
7432
7565
  return { kind: "ambiguous", candidates: byType };
7433
7566
  }
7434
7567
  function describeNeoScriptDeclaredConstructors(className, constructors) {
7435
7568
  return constructors.map(
7436
- (constructor2) => `${className}(${constructor2.parameters.map((parameter4) => `${parameter4.name}${parameter4.required ? "" : "?"}`).join(", ")})`
7569
+ (constructor2) => `${className}(${constructor2.parameters.map(describeParameter).join(", ")})`
7437
7570
  ).join(", ");
7438
7571
  }
7572
+ function describeParameter(parameter4) {
7573
+ const nullability = parameter4.required ? "" : "?";
7574
+ const defaulted = parameter4.defaultValue === void 0 ? "" : ` = ${parameter4.defaultValue.displayText}`;
7575
+ return `${parameter4.name}${nullability}${defaulted}`;
7576
+ }
7439
7577
  var init_declared_constructors = __esm({
7440
7578
  "../packages/neoscript-language/src/declared-constructors.ts"() {
7441
7579
  "use strict";
7580
+ init_project();
7442
7581
  }
7443
7582
  });
7444
7583
 
@@ -8829,6 +8968,12 @@ function collectReturns(statements) {
8829
8968
  }
8830
8969
  return result;
8831
8970
  }
8971
+ function functionArityMessage(name, minimum, maximum, got) {
8972
+ if (minimum === maximum) {
8973
+ return `Function '${name}' expects ${maximum} argument${maximum === 1 ? "" : "s"}, got ${got}.`;
8974
+ }
8975
+ return `Function '${name}' expects between ${minimum} and ${maximum} arguments, got ${got}.`;
8976
+ }
8832
8977
  function requireArgCount(name, args, expected, pos) {
8833
8978
  if (args.length === expected) return;
8834
8979
  throw new CompileError(
@@ -12673,9 +12818,28 @@ var init_strict_resolver = __esm({
12673
12818
  }));
12674
12819
  }
12675
12820
  }
12676
- if (argumentsList2.length !== parameters.length) {
12821
+ const minimumArguments = parameters.filter(
12822
+ (parameter4) => !neoScriptParameterIsOmittable(parameter4)
12823
+ ).length;
12824
+ if (argumentsList2.length < minimumArguments) {
12677
12825
  throw new CompileError(
12678
- `Function '${symbol.name}' expects ${parameters.length} argument${parameters.length === 1 ? "" : "s"}, got ${argumentsList2.length}.`,
12826
+ functionArityMessage(
12827
+ symbol.name,
12828
+ minimumArguments,
12829
+ parameters.length,
12830
+ argumentsList2.length
12831
+ ),
12832
+ pos
12833
+ );
12834
+ }
12835
+ if (argumentsList2.length > parameters.length) {
12836
+ throw new CompileError(
12837
+ functionArityMessage(
12838
+ symbol.name,
12839
+ minimumArguments,
12840
+ parameters.length,
12841
+ argumentsList2.length
12842
+ ),
12679
12843
  pos
12680
12844
  );
12681
12845
  }
@@ -16595,12 +16759,25 @@ var init_project_source_parser = __esm({
16595
16759
  const annotations = this.parseAnnotations();
16596
16760
  const type = this.parseType();
16597
16761
  const name = this.expectName("parameter name");
16762
+ let defaultValue;
16763
+ if (this.eat("=")) {
16764
+ const expressionStart = this.peek();
16765
+ defaultValue = this.captureUntilTopLevel(/* @__PURE__ */ new Set([",", ")"]), false);
16766
+ if (defaultValue.text.trim().length === 0) {
16767
+ throw this.failure(
16768
+ "missing-parameter-default",
16769
+ `Parameter '${name.text}' declares '=' but no default value. Provide a constant expression or remove the '='.`,
16770
+ expressionStart
16771
+ );
16772
+ }
16773
+ }
16598
16774
  parameters.push({
16599
16775
  annotations,
16600
16776
  type,
16601
16777
  name: name.text,
16602
16778
  nameRange: name.range,
16603
- range: rangeFrom(start, name)
16779
+ ...defaultValue ? { defaultValue } : {},
16780
+ range: rangeFrom(start, this.previous())
16604
16781
  });
16605
16782
  if (!this.eat(",") && !this.at(")")) {
16606
16783
  throw this.failure(
@@ -17173,7 +17350,7 @@ var init_project_schema_contract_generated = __esm({
17173
17350
  "../packages/neoscript-language/src/project-schema-contract.generated.ts"() {
17174
17351
  "use strict";
17175
17352
  PROJECT_SCHEMA_MANIFEST_FORMAT_VERSION = 3;
17176
- PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION = "3.9";
17353
+ PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION = "3.10";
17177
17354
  PROJECT_FILE_UPLOAD_BATCH_SIZE = 32;
17178
17355
  NEO_PROJECT_SOURCE_RECORD_CONTRACT = {
17179
17356
  "recordFields": {
@@ -19272,6 +19449,24 @@ var init_project_source_construction_diagnostics = __esm({
19272
19449
  "unbound-constructor-argument": "error",
19273
19450
  /** §2.6. No overload's parameter-name set matches the call. */
19274
19451
  "no-matching-constructor-overload": "error",
19452
+ /**
19453
+ * P65 §2.2. Two overload candidates tie under the subset match after the
19454
+ * fewest-fill-ins betterness and the type tie-break; the message lists the
19455
+ * candidates the call could not choose between.
19456
+ */
19457
+ "ambiguous-constructor-call": "error",
19458
+ /**
19459
+ * P65 §1.3. A defaulted parameter declared before a non-defaulted one.
19460
+ * The code string is shared with `src/models/neoscript/parameter-defaults.ts`
19461
+ * so the push guards and the compiler name one rule identically.
19462
+ */
19463
+ "default-before-required-parameter": "error",
19464
+ /**
19465
+ * P65 §1.2. A parameter default that does not fit the parameter's declared
19466
+ * type — a `null` default on a non-nullable parameter included. Shared with
19467
+ * the push-guard validator, like the placement code above.
19468
+ */
19469
+ "parameter-default-type-mismatch": "error",
19275
19470
  /** §2.5 g. An initializer key naming no member of the constructed class. */
19276
19471
  "unknown-initializer-member": "error",
19277
19472
  /**
@@ -19541,9 +19736,13 @@ function resolveInvokedConstructor(declaration, call, diagnostics) {
19541
19736
  return true;
19542
19737
  }
19543
19738
  if (headerParameters.length === 0) return true;
19739
+ if (parameterListIsFullyDefaulted(headerParameters)) return true;
19740
+ const mandatory = headerParameters.filter(
19741
+ (parameter4) => parameter4.defaultValue === void 0
19742
+ );
19544
19743
  diagnostics.push({
19545
19744
  code: "required-constructor-not-invoked",
19546
- message: `Class '${declaration.name}' declares the required constructor ${describeParameterList(declaration.name, headerParameters)}, so it cannot be constructed without passing ${describeNameList(headerParameters.map((parameter4) => parameter4.name))}.`,
19745
+ message: `Class '${declaration.name}' declares the required constructor ${describeParameterList(declaration.name, headerParameters)}, so it cannot be constructed without passing ${describeNameList(mandatory.map((parameter4) => parameter4.name))}.`,
19547
19746
  anchor: { kind: "site" }
19548
19747
  });
19549
19748
  return true;
@@ -19553,7 +19752,7 @@ function resolveInvokedConstructor(declaration, call, diagnostics) {
19553
19752
  }
19554
19753
  if (call.argumentNames.length === 0) {
19555
19754
  return declaration.constructors.some(
19556
- (constructor2) => constructor2.parameters.length === 0
19755
+ (constructor2) => parameterListIsFullyDefaulted(constructor2.parameters)
19557
19756
  );
19558
19757
  }
19559
19758
  if (declaration.constructors.length === 1) {
@@ -19565,13 +19764,17 @@ function resolveInvokedConstructor(declaration, call, diagnostics) {
19565
19764
  );
19566
19765
  return true;
19567
19766
  }
19568
- const key = argumentNameSetKey(
19569
- call.argumentNames.filter((name) => name !== null)
19767
+ const suppliedNames = call.argumentNames.filter(
19768
+ (name) => name !== null
19570
19769
  );
19571
19770
  const matches = declaration.constructors.filter(
19572
- (constructor2) => argumentNameSetKey(
19573
- constructor2.parameters.map((parameter4) => parameter4.name)
19574
- ) === key
19771
+ (constructor2) => neoScriptCallMatchesParameters(
19772
+ suppliedNames,
19773
+ constructor2.parameters.map((parameter4) => ({
19774
+ name: parameter4.name,
19775
+ defaulted: parameter4.defaultValue !== void 0
19776
+ }))
19777
+ )
19575
19778
  );
19576
19779
  if (matches.length > 0) return true;
19577
19780
  diagnostics.push({
@@ -19606,7 +19809,7 @@ function validateArgumentsAgainstParameters(className, parameters, call, diagnos
19606
19809
  });
19607
19810
  });
19608
19811
  const missing = parameters.filter(
19609
- (parameter4) => !supplied.has(parameter4.name.toLowerCase())
19812
+ (parameter4) => parameter4.defaultValue === void 0 && !supplied.has(parameter4.name.toLowerCase())
19610
19813
  );
19611
19814
  if (missing.length === 0) return;
19612
19815
  diagnostics.push({
@@ -19615,6 +19818,9 @@ function validateArgumentsAgainstParameters(className, parameters, call, diagnos
19615
19818
  anchor: { kind: "site" }
19616
19819
  });
19617
19820
  }
19821
+ function parameterListIsFullyDefaulted(parameters) {
19822
+ return parameters.every((parameter4) => parameter4.defaultValue !== void 0);
19823
+ }
19618
19824
  function validateInitializerEntries(index, entry, call, diagnostics) {
19619
19825
  if (call.initializerNames.length === 0) return;
19620
19826
  const chain = baseChain(index, entry);
@@ -19746,13 +19952,12 @@ function substitute(type, bindings) {
19746
19952
  arguments: type.arguments.map((argument2) => substitute(argument2, bindings))
19747
19953
  };
19748
19954
  }
19749
- function argumentNameSetKey(names) {
19750
- return [...names].map((name) => name.toLowerCase()).sort().join(",");
19751
- }
19752
19955
  function describeParameterList(className, parameters) {
19753
- const rendered = parameters.map(
19754
- (parameter4) => `${parameter4.name}${parameter4.type.nullable ? "?" : ""}`
19755
- ).join(", ");
19956
+ const rendered = parameters.map((parameter4) => {
19957
+ const nullability = parameter4.type.nullable ? "?" : "";
19958
+ const defaulted = parameter4.defaultValue === void 0 ? "" : ` = ${parameter4.defaultValue.text}`;
19959
+ return `${parameter4.name}${nullability}${defaulted}`;
19960
+ }).join(", ");
19756
19961
  return `${className}(${rendered})`;
19757
19962
  }
19758
19963
  function describeNameList(names) {
@@ -19781,6 +19986,7 @@ function push(diagnostics, uri, range2, code, message, related2 = []) {
19781
19986
  var init_project_source_settlement = __esm({
19782
19987
  "../packages/neoscript-language/src/project-source-settlement.ts"() {
19783
19988
  "use strict";
19989
+ init_declared_constructors();
19784
19990
  init_project_source_construction_diagnostics();
19785
19991
  init_strict_compile_error();
19786
19992
  init_strict_parser();
@@ -24443,6 +24649,223 @@ var init_project_source_type_checker = __esm({
24443
24649
  }
24444
24650
  });
24445
24651
 
24652
+ // ../packages/neoscript-language/src/project-source-parameter-defaults.ts
24653
+ function validateProjectSourceParameterDefaults(documents) {
24654
+ const diagnostics = [];
24655
+ const enumOptions = collectEnumOptions(documents);
24656
+ for (const [uri, document] of documents) {
24657
+ for (const declaration of document.declarations) {
24658
+ if (declaration.kind === "class") {
24659
+ if (declaration.headerParameters !== void 0) {
24660
+ validateParameterList(
24661
+ uri,
24662
+ declaration.headerParameters,
24663
+ { deferred: false },
24664
+ enumOptions,
24665
+ diagnostics
24666
+ );
24667
+ }
24668
+ for (const constructor2 of declaration.constructors) {
24669
+ validateParameterList(
24670
+ uri,
24671
+ constructor2.parameters,
24672
+ { deferred: false },
24673
+ enumOptions,
24674
+ diagnostics
24675
+ );
24676
+ }
24677
+ }
24678
+ if (declaration.kind === "class" || declaration.kind === "interface") {
24679
+ for (const member of declaration.members) {
24680
+ if (member.kind !== "function") continue;
24681
+ validateParameterList(
24682
+ uri,
24683
+ member.parameters,
24684
+ { deferred: member.modifiers.includes("async") },
24685
+ enumOptions,
24686
+ diagnostics
24687
+ );
24688
+ }
24689
+ }
24690
+ }
24691
+ }
24692
+ return diagnostics;
24693
+ }
24694
+ function collectEnumOptions(documents) {
24695
+ const options = /* @__PURE__ */ new Map();
24696
+ for (const document of documents.values()) {
24697
+ for (const declaration of document.declarations) {
24698
+ if (declaration.kind !== "enum") continue;
24699
+ const names = options.get(declaration.name) ?? options.set(declaration.name, /* @__PURE__ */ new Set()).get(declaration.name);
24700
+ for (const option of declaration.options) names.add(option.name);
24701
+ }
24702
+ }
24703
+ return options;
24704
+ }
24705
+ function validateParameterList(uri, parameters, context, enumOptions, diagnostics) {
24706
+ let lastNonDefaultedIndex = -1;
24707
+ for (let index = parameters.length - 1; index >= 0; index -= 1) {
24708
+ if (parameters[index].defaultValue === void 0) {
24709
+ lastNonDefaultedIndex = index;
24710
+ break;
24711
+ }
24712
+ }
24713
+ parameters.forEach((parameter4, index) => {
24714
+ const defaultValue = parameter4.defaultValue;
24715
+ if (defaultValue === void 0) return;
24716
+ if (context.deferred) {
24717
+ diagnostics.push({
24718
+ uri,
24719
+ range: defaultValue.range,
24720
+ severity: "error",
24721
+ source: "neo-project",
24722
+ code: PARAMETER_DEFAULT_ON_DEFERRED_FUNCTION,
24723
+ message: `Parameter '${parameter4.name}' of a deferred function cannot declare a default: generated C# appends a trailing deferred-completion parameter, which a defaulted parameter may not precede.`
24724
+ });
24725
+ }
24726
+ if (index < lastNonDefaultedIndex) {
24727
+ diagnostics.push({
24728
+ uri,
24729
+ range: parameter4.range,
24730
+ severity: "error",
24731
+ source: "neo-project",
24732
+ code: DEFAULT_BEFORE_REQUIRED_PARAMETER,
24733
+ message: `Parameter '${parameter4.name}' declares a default before parameter '${parameters[lastNonDefaultedIndex].name}', which has none. Defaulted parameters must come after every non-defaulted parameter.`
24734
+ });
24735
+ }
24736
+ validateDefaultExpression(
24737
+ uri,
24738
+ parameter4,
24739
+ defaultValue,
24740
+ enumOptions,
24741
+ diagnostics
24742
+ );
24743
+ });
24744
+ }
24745
+ function validateDefaultExpression(uri, parameter4, defaultValue, enumOptions, diagnostics) {
24746
+ const constant = classifyConstantDefault(defaultValue.text);
24747
+ if (constant === null) {
24748
+ diagnostics.push({
24749
+ uri,
24750
+ range: defaultValue.range,
24751
+ severity: "error",
24752
+ source: "neo-project",
24753
+ code: NON_CONSTANT_PARAMETER_DEFAULT,
24754
+ message: `Parameter '${parameter4.name}' default must be a constant: a bool, number, or string literal, a leading-dot enum option, or null.`
24755
+ });
24756
+ return;
24757
+ }
24758
+ const mismatch = defaultTypeMismatch(
24759
+ parameter4.type,
24760
+ constant,
24761
+ enumOptions,
24762
+ parameter4.name
24763
+ );
24764
+ if (mismatch === null) return;
24765
+ diagnostics.push({
24766
+ uri,
24767
+ range: defaultValue.range,
24768
+ severity: "error",
24769
+ source: "neo-project",
24770
+ code: PARAMETER_DEFAULT_TYPE_MISMATCH,
24771
+ message: mismatch
24772
+ });
24773
+ }
24774
+ function classifyConstantDefault(text) {
24775
+ let expression;
24776
+ try {
24777
+ expression = parseExpression(text);
24778
+ } catch {
24779
+ return null;
24780
+ }
24781
+ return classifyConstantExpression(expression);
24782
+ }
24783
+ function classifyConstantExpression(expression) {
24784
+ switch (expression.kind) {
24785
+ case "litNull":
24786
+ return { kind: "null" };
24787
+ case "litBool":
24788
+ return { kind: "bool" };
24789
+ case "litInt":
24790
+ return { kind: "int" };
24791
+ case "litFloat":
24792
+ return { kind: "float" };
24793
+ case "litString":
24794
+ return { kind: "string" };
24795
+ case "contextualEnum":
24796
+ return { kind: "enumOption", optionName: expression.name };
24797
+ case "unary": {
24798
+ if (expression.op !== "-") return null;
24799
+ const operand = classifyConstantExpression(expression.operand);
24800
+ if (operand === null) return null;
24801
+ if (operand.kind !== "int" && operand.kind !== "float") return null;
24802
+ return operand;
24803
+ }
24804
+ default:
24805
+ return null;
24806
+ }
24807
+ }
24808
+ function defaultTypeMismatch(type, constant, enumOptions, parameterName) {
24809
+ if (constant.kind === "null") {
24810
+ if (type.nullable) return null;
24811
+ return `Parameter '${parameterName}' defaults to null, but its type '${formatSourceType(type)}' is not nullable.`;
24812
+ }
24813
+ const declaredEnumOptions = enumOptions.get(type.name);
24814
+ if (constant.kind === "enumOption") {
24815
+ if (declaredEnumOptions === void 0) {
24816
+ return `Parameter '${parameterName}' defaults to enum option '.${constant.optionName}', but its type '${formatSourceType(type)}' is not an enum.`;
24817
+ }
24818
+ if (!declaredEnumOptions.has(constant.optionName)) {
24819
+ return `Parameter '${parameterName}' defaults to '.${constant.optionName}', which enum '${type.name}' does not declare.`;
24820
+ }
24821
+ return null;
24822
+ }
24823
+ if (constantKindMatchesPrimitive(type.name, constant.kind)) return null;
24824
+ if (PRIMITIVE_PARAMETER_TYPES.has(type.name) || declaredEnumOptions !== void 0) {
24825
+ return `Parameter '${parameterName}' default is a ${describeConstant(constant)}, which does not match its declared type '${formatSourceType(type)}'.`;
24826
+ }
24827
+ return `Parameter '${parameterName}' of type '${formatSourceType(type)}' can only default to null${type.nullable ? "" : ", and only when the type is nullable"}.`;
24828
+ }
24829
+ function constantKindMatchesPrimitive(typeName, kind) {
24830
+ if (typeName === "bool") return kind === "bool";
24831
+ if (typeName === "int") return kind === "int";
24832
+ if (typeName === "float") return kind === "int" || kind === "float";
24833
+ if (typeName === "decimal") return kind === "int" || kind === "float";
24834
+ if (typeName === "string") return kind === "string";
24835
+ return false;
24836
+ }
24837
+ function describeConstant(constant) {
24838
+ if (constant.kind === "bool") return "bool literal";
24839
+ if (constant.kind === "string") return "string literal";
24840
+ if (constant.kind === "int") return "whole-number literal";
24841
+ return "fractional number literal";
24842
+ }
24843
+ function formatSourceType(type) {
24844
+ const argumentsText = type.typeArguments.length === 0 ? "" : `<${type.typeArguments.map(formatSourceType).join(", ")}>`;
24845
+ return `${type.name}${argumentsText}${type.nullable ? "?" : ""}`;
24846
+ }
24847
+ var PARAMETER_DEFAULT_DIAGNOSTIC_CODES, DEFAULT_BEFORE_REQUIRED_PARAMETER, PARAMETER_DEFAULT_TYPE_MISMATCH, NON_CONSTANT_PARAMETER_DEFAULT, PARAMETER_DEFAULT_ON_DEFERRED_FUNCTION, PRIMITIVE_PARAMETER_TYPES;
24848
+ var init_project_source_parameter_defaults = __esm({
24849
+ "../packages/neoscript-language/src/project-source-parameter-defaults.ts"() {
24850
+ "use strict";
24851
+ init_language_spec();
24852
+ init_strict_parser();
24853
+ PARAMETER_DEFAULT_DIAGNOSTIC_CODES = {
24854
+ defaultBeforeRequiredParameter: "default-before-required-parameter",
24855
+ parameterDefaultTypeMismatch: "parameter-default-type-mismatch",
24856
+ nonConstantParameterDefault: "non-constant-parameter-default",
24857
+ parameterDefaultOnDeferredFunction: "parameter-default-on-deferred-function"
24858
+ };
24859
+ ({
24860
+ defaultBeforeRequiredParameter: DEFAULT_BEFORE_REQUIRED_PARAMETER,
24861
+ parameterDefaultTypeMismatch: PARAMETER_DEFAULT_TYPE_MISMATCH,
24862
+ nonConstantParameterDefault: NON_CONSTANT_PARAMETER_DEFAULT,
24863
+ parameterDefaultOnDeferredFunction: PARAMETER_DEFAULT_ON_DEFERRED_FUNCTION
24864
+ } = PARAMETER_DEFAULT_DIAGNOSTIC_CODES);
24865
+ PRIMITIVE_PARAMETER_TYPES = new Set(NEOSCRIPT_PRIMITIVE_TYPES);
24866
+ }
24867
+ });
24868
+
24446
24869
  // ../packages/neoscript-language/src/project-source-analysis.ts
24447
24870
  function isSystemReservedRecordId(id2) {
24448
24871
  if (id2 === null) return false;
@@ -24500,6 +24923,7 @@ function analyzeNeoProjectSources(inputs, parsedDocuments = /* @__PURE__ */ new
24500
24923
  validateSystemAnnotationAuthoring(documents, diagnostics);
24501
24924
  validateTypeReferences(documents, symbols, diagnostics);
24502
24925
  diagnostics.push(...validateProjectSourceTypes(documents));
24926
+ diagnostics.push(...validateProjectSourceParameterDefaults(documents));
24503
24927
  diagnostics.push(...validateProjectSourceSettlement(documents));
24504
24928
  diagnostics.push(...validateProjectSourceSemantics(documents));
24505
24929
  const bodyCompilation = compileProjectSourceBodies(documents);
@@ -25108,6 +25532,7 @@ var init_project_source_analysis = __esm({
25108
25532
  init_project_source_settlement();
25109
25533
  init_project_source_script_compiler();
25110
25534
  init_project_source_type_checker();
25535
+ init_project_source_parameter_defaults();
25111
25536
  BUILTIN_TYPE_NAMES = /* @__PURE__ */ new Set([
25112
25537
  ...NEOSCRIPT_PRIMITIVE_TYPES,
25113
25538
  ...NEOSCRIPT_BUILTIN_TYPES,
@@ -25427,7 +25852,9 @@ function projectCompletions(analysis, document, position) {
25427
25852
  items: constructorFields.map((field) => ({
25428
25853
  label: field.name,
25429
25854
  kind: "property",
25430
- detail: field.type,
25855
+ // P65 §6. C#-style square brackets mark a defaulted parameter as
25856
+ // omittable at the call site.
25857
+ detail: field.defaultText === void 0 ? field.type : `[${field.type} = ${field.defaultText}]`,
25431
25858
  insertText: `${field.name}: `
25432
25859
  }))
25433
25860
  };
@@ -25862,7 +26289,11 @@ function declaredConstructorNamedArguments(analysis, typeName, used) {
25862
26289
  return [...fields.values()];
25863
26290
  }
25864
26291
  function parameterArgumentField(parameter4) {
25865
- return { name: parameter4.name, type: sourceTypeText(parameter4.type) };
26292
+ return {
26293
+ name: parameter4.name,
26294
+ type: sourceTypeText(parameter4.type),
26295
+ ...parameter4.defaultValue === void 0 ? {} : { defaultText: parameter4.defaultValue.text }
26296
+ };
25866
26297
  }
25867
26298
  function projectInitializerMemberCompletions(analysis, document, position) {
25868
26299
  const site = constructionSiteAt(analysis, document, position);
@@ -25922,6 +26353,13 @@ function constructibleMembers(analysis, typeName) {
25922
26353
  }
25923
26354
  return [...members.values()];
25924
26355
  }
26356
+ function sourceParameterSignatureText(parameter4) {
26357
+ return constructorParameterLabel(sourceParameterProjection(parameter4));
26358
+ }
26359
+ function functionParameterLabel(parameter4) {
26360
+ const suffix = parameter4.defaultValue === void 0 ? "" : ` = ${parameter4.defaultValue.text}`;
26361
+ return `${parameter4.type.name} ${parameter4.name}${suffix}`;
26362
+ }
25925
26363
  function sourceTypeText(type) {
25926
26364
  const args = type.typeArguments.length > 0 ? `<${type.typeArguments.map(sourceTypeText).join(", ")}>` : "";
25927
26365
  return `${type.name}${args}${type.nullable ? "?" : ""}`;
@@ -26048,7 +26486,7 @@ function projectConstructionContractMarkdown(analysis, className) {
26048
26486
  const contract = classConstructionContract(index, className);
26049
26487
  if (!contract) return "";
26050
26488
  if (contract.kind === "required") {
26051
- const parameters = contract.parameters.map((parameter4) => `${sourceTypeText(parameter4.type)} ${parameter4.name}`).join(", ");
26489
+ const parameters = contract.parameters.map(sourceParameterSignatureText).join(", ");
26052
26490
  return `
26053
26491
 
26054
26492
  Construct with \`new(${parameters})\` \u2014 this class declares a required constructor, so the implicit \`new\` is unavailable.`;
@@ -26063,9 +26501,7 @@ Construct with \`new(${parameters})\` \u2014 this class declares a required cons
26063
26501
  }
26064
26502
  if (contract.kind === "declared") {
26065
26503
  const overloads = contract.constructors.map(
26066
- (constructor2) => `\`${className}(${constructor2.parameters.map(
26067
- (parameter4) => `${sourceTypeText(parameter4.type)} ${parameter4.name}`
26068
- ).join(", ")})\``
26504
+ (constructor2) => `\`${className}(${constructor2.parameters.map(sourceParameterSignatureText).join(", ")})\``
26069
26505
  ).join(", ");
26070
26506
  lines.push(`Constructors: ${overloads}.`);
26071
26507
  }
@@ -26187,13 +26623,11 @@ function projectSignatureHelp(analysis, document, position) {
26187
26623
  if (functions.length === 0) return null;
26188
26624
  return {
26189
26625
  signatures: functions.map(({ owner, member }) => {
26190
- const parameters = member.parameters.map(
26191
- (parameter4) => `${parameter4.type.name} ${parameter4.name}`
26192
- );
26626
+ const parameters = member.parameters.map(functionParameterLabel);
26193
26627
  return {
26194
26628
  label: `${member.type.name} ${owner}.${member.name}(${parameters.join(", ")})`,
26195
26629
  parameters: member.parameters.map((parameter4) => ({
26196
- label: `${parameter4.type.name} ${parameter4.name}`
26630
+ label: functionParameterLabel(parameter4)
26197
26631
  }))
26198
26632
  };
26199
26633
  }),
@@ -26959,7 +27393,10 @@ function findTypeDeclaration(analysis, name) {
26959
27393
  return void 0;
26960
27394
  }
26961
27395
  function constructorParameterLabel(parameter4) {
26962
- return `${parameter4.type} ${parameter4.name}`;
27396
+ return `${parameter4.type} ${parameter4.name}${parameterDefaultSuffix2(parameter4)}`;
27397
+ }
27398
+ function parameterDefaultSuffix2(parameter4) {
27399
+ return parameter4.defaultText === void 0 ? "" : ` = ${parameter4.defaultText}`;
26963
27400
  }
26964
27401
  function projectConstructorTypeName(analysis, document, callee, beforeCallee) {
26965
27402
  if (beforeCallee?.text === "new") return callee.text;
@@ -26985,7 +27422,11 @@ function declarationConstructorParameters(declaration) {
26985
27422
  ).map((member) => ({ type: member.type.name, name: member.name }));
26986
27423
  }
26987
27424
  function sourceParameterProjection(parameter4) {
26988
- return { type: sourceTypeText(parameter4.type), name: parameter4.name };
27425
+ return {
27426
+ type: sourceTypeText(parameter4.type),
27427
+ name: parameter4.name,
27428
+ ...parameter4.defaultValue === void 0 ? {} : { defaultText: parameter4.defaultValue.text }
27429
+ };
26989
27430
  }
26990
27431
  function graphConstructorParameters(typeName) {
26991
27432
  switch (typeName) {
@@ -27104,6 +27545,9 @@ function projectConstructionQuickFixes(analysis, document, diagnostic) {
27104
27545
  if (diagnostic.code === "unknown-identifier") {
27105
27546
  return moveParametersToClassHeaderFixes(analysis, document, diagnostic);
27106
27547
  }
27548
+ if (diagnostic.code === "default-before-required-parameter") {
27549
+ return moveDefaultedParameterFixes(analysis, document, diagnostic);
27550
+ }
27107
27551
  return [];
27108
27552
  }
27109
27553
  function settleRequiredMemberFixes(analysis, document, diagnostic) {
@@ -27209,10 +27653,13 @@ function placeholderValue(analysis, index, type, depth) {
27209
27653
  if (declaration.modifiers.includes("abstract")) return null;
27210
27654
  const contract = classConstructionContract(index, type.name);
27211
27655
  if (contract?.kind !== "required") return "new()";
27212
- if (contract.parameters.length === 0) return "new()";
27656
+ const mandatory = contract.parameters.filter(
27657
+ (parameter4) => parameter4.defaultValue === void 0
27658
+ );
27659
+ if (mandatory.length === 0) return "new()";
27213
27660
  if (depth > 0) return null;
27214
27661
  const args = [];
27215
- for (const parameter4 of contract.parameters) {
27662
+ for (const parameter4 of mandatory) {
27216
27663
  const value = placeholderValue(analysis, index, parameter4.type, depth + 1);
27217
27664
  if (value === null) return null;
27218
27665
  args.push(`${parameter4.name}: ${value}`);
@@ -27404,6 +27851,71 @@ function innerBodyText(constructor2) {
27404
27851
  const trimmed = constructor2.body.text.trim();
27405
27852
  return trimmed.startsWith("{") && trimmed.endsWith("}") ? trimmed.slice(1, -1) : trimmed;
27406
27853
  }
27854
+ function moveDefaultedParameterFixes(analysis, document, diagnostic) {
27855
+ const source = analysis.documents.get(document.uri);
27856
+ if (!source) return [];
27857
+ const parameters = parameterListAt(source.declarations, diagnostic.range);
27858
+ if (parameters === null) return [];
27859
+ const first = parameters[0];
27860
+ const last = parameters[parameters.length - 1];
27861
+ if (!first || !last) return [];
27862
+ const text = new SourceText(document.text);
27863
+ const authored = (parameter4) => text.text.slice(
27864
+ text.offsetAt(parameter4.range.start),
27865
+ text.offsetAt(parameter4.range.end)
27866
+ );
27867
+ const reordered = [
27868
+ ...parameters.filter((parameter4) => parameter4.defaultValue === void 0),
27869
+ ...parameters.filter((parameter4) => parameter4.defaultValue !== void 0)
27870
+ ];
27871
+ return [
27872
+ {
27873
+ title: "Move defaulted parameters after required parameters",
27874
+ kind: "quickfix",
27875
+ diagnostics: [diagnostic],
27876
+ edit: {
27877
+ changes: {
27878
+ [document.uri]: [
27879
+ {
27880
+ range: {
27881
+ start: first.range.start,
27882
+ end: last.range.end
27883
+ },
27884
+ newText: reordered.map(authored).join(", ")
27885
+ }
27886
+ ]
27887
+ }
27888
+ },
27889
+ preferred: true
27890
+ }
27891
+ ];
27892
+ }
27893
+ function parameterListAt(declarations, range2) {
27894
+ for (const declaration of declarations) {
27895
+ if (declaration.kind !== "class" && declaration.kind !== "interface") {
27896
+ continue;
27897
+ }
27898
+ const lists = [];
27899
+ if (declaration.kind === "class") {
27900
+ if (declaration.headerParameters !== void 0) {
27901
+ lists.push(declaration.headerParameters);
27902
+ }
27903
+ for (const constructor2 of declaration.constructors) {
27904
+ lists.push(constructor2.parameters);
27905
+ }
27906
+ }
27907
+ for (const member of declaration.members) {
27908
+ if (member.kind === "function") lists.push(member.parameters);
27909
+ }
27910
+ for (const list of lists) {
27911
+ const hit = list.some(
27912
+ (parameter4) => rangeContains(parameter4.range, range2.start)
27913
+ );
27914
+ if (hit) return list;
27915
+ }
27916
+ }
27917
+ return null;
27918
+ }
27407
27919
  var NEW_CONSTRUCTIBLE_BUILTIN_TYPES;
27408
27920
  var init_project_source_construction_quick_fixes = __esm({
27409
27921
  "../packages/neoscript-language/src/project-source-construction-quick-fixes.ts"() {
@@ -27560,6 +28072,7 @@ function manifestParameter(uri, parameter4) {
27560
28072
  name: parameter4.name,
27561
28073
  type: manifestType(parameter4.type),
27562
28074
  annotations: manifestAnnotations(parameter4.annotations),
28075
+ default: parameter4.defaultValue?.text ?? null,
27563
28076
  source: { uri, range: parameter4.range }
27564
28077
  };
27565
28078
  }
@@ -27970,12 +28483,21 @@ function assertBaseClauseArguments(value, path) {
27970
28483
  }
27971
28484
  function assertParameter(value, path) {
27972
28485
  const parameter4 = record(value, path);
27973
- exactKeys(parameter4, path, ["name", "type", "annotations", "source"]);
28486
+ exactKeys(parameter4, path, [
28487
+ "name",
28488
+ "type",
28489
+ "annotations",
28490
+ "default",
28491
+ "source"
28492
+ ]);
27974
28493
  string(parameter4.name, `${path}.name`);
27975
28494
  assertType(parameter4.type, `${path}.type`);
27976
28495
  array(parameter4.annotations, `${path}.annotations`).forEach(
27977
28496
  (annotation2, index) => assertAnnotation(annotation2, `${path}.annotations[${index}]`)
27978
28497
  );
28498
+ if (parameter4.default !== null) {
28499
+ string(parameter4.default, `${path}.default`);
28500
+ }
27979
28501
  assertLocation(parameter4.source, `${path}.source`);
27980
28502
  }
27981
28503
  function assertMember(value, path) {
@@ -28408,6 +28930,7 @@ function projectSchemaManifest(input, options = {}) {
28408
28930
  members: memberById,
28409
28931
  classes: schemaClassById,
28410
28932
  interfaces: interfaceById,
28933
+ enums: indexById(enums, "ProjectSchemaManifest.enums"),
28411
28934
  genericNames,
28412
28935
  effectiveWritabilityByMemberId: effectiveMemberWritability(
28413
28936
  members,
@@ -28469,7 +28992,8 @@ function groupDeclaredConstructors(declaredConstructors2, environment) {
28469
28992
  (parameter4) => ({
28470
28993
  name: parameter4.name,
28471
28994
  type: parameter4.type,
28472
- required: parameter4.type.nullable !== true
28995
+ required: parameter4.type.nullable !== true,
28996
+ ...parameter4.defaultValue === void 0 ? {} : { defaultValue: parameter4.defaultValue }
28473
28997
  })
28474
28998
  ),
28475
28999
  ...documentation === void 0 ? {} : { documentation },
@@ -29479,6 +30003,11 @@ function argumentsList(value, environment, field) {
29479
30003
  environment,
29480
30004
  `${field}.arguments[${index}].type`
29481
30005
  ),
30006
+ ...manifestParameterDefault(
30007
+ argument2,
30008
+ environment,
30009
+ `${field}.arguments[${index}]`
30010
+ ),
29482
30011
  ...spanAndSelectionLocations(
29483
30012
  argument2.source,
29484
30013
  argument2.selectionSpan ?? argument2.source,
@@ -29487,6 +30016,54 @@ function argumentsList(value, environment, field) {
29487
30016
  )
29488
30017
  }));
29489
30018
  }
30019
+ function neoScriptParameterDefaultDisplayText(options) {
30020
+ const { value, kind } = options;
30021
+ if (value === null) return "null";
30022
+ if (kind === "enum") return `.${options.enumOptionName ?? String(value)}`;
30023
+ if (kind === "decimal" && typeof value === "string") return value;
30024
+ if (typeof value === "string") return JSON.stringify(value);
30025
+ return String(value);
30026
+ }
30027
+ function manifestParameterDefault(argument2, environment, field) {
30028
+ const declared = optionalRecord(argument2.default);
30029
+ if (declared === void 0) return {};
30030
+ const value = constantDefaultValue(declared.value, `${field}.default.value`);
30031
+ const type = record2(argument2.type, `${field}.type`);
30032
+ const kind = string2(type.kind, `${field}.type.kind`);
30033
+ const enumOptionName = kind === "enum" && typeof value === "string" ? manifestEnumOptionName(
30034
+ string2(type.enumId, `${field}.type.enumId`),
30035
+ value,
30036
+ environment
30037
+ ) : void 0;
30038
+ return {
30039
+ defaultValue: {
30040
+ displayText: neoScriptParameterDefaultDisplayText({
30041
+ value,
30042
+ kind: kind === "enum" || kind === "decimal" ? kind : "other",
30043
+ ...enumOptionName === void 0 ? {} : { enumOptionName }
30044
+ }),
30045
+ value
30046
+ }
30047
+ };
30048
+ }
30049
+ function constantDefaultValue(value, field) {
30050
+ if (value !== null && typeof value !== "boolean" && typeof value !== "number" && typeof value !== "string") {
30051
+ throw new Error(
30052
+ `${field} must be a \xA71.2 constant (boolean, number, string, or null), received ${JSON.stringify(value)}.`
30053
+ );
30054
+ }
30055
+ return value;
30056
+ }
30057
+ function manifestEnumOptionName(enumId, optionId, environment) {
30058
+ const schemaEnum = environment.enums.get(enumId);
30059
+ if (schemaEnum === void 0) return void 0;
30060
+ const options = records(schemaEnum.options ?? [], `enum ${enumId}.options`);
30061
+ const option = options.find(
30062
+ (candidate) => candidate.id === optionId || candidate.key === optionId
30063
+ );
30064
+ if (option === void 0) return void 0;
30065
+ return typeof option.name === "string" ? option.name : void 0;
30066
+ }
29490
30067
  function sourceLocation(value, environment, field) {
29491
30068
  const source = optionalRecord(value);
29492
30069
  if (!source) return {};
@@ -30436,6 +31013,7 @@ var init_src = __esm({
30436
31013
  init_project_source_construction_diagnostics();
30437
31014
  init_project_source_construction_quick_fixes();
30438
31015
  init_project_source_manifest();
31016
+ init_project_source_parameter_defaults();
30439
31017
  init_project_source_settlement();
30440
31018
  init_project_source_parser();
30441
31019
  init_project_source_script_compiler();
@@ -32401,10 +32979,7 @@ function memberToDocumentFields(member, baseData3) {
32401
32979
  }
32402
32980
  if (member.kind === "function" || member.kind === "scriptFunction") {
32403
32981
  fields.returnTypeInfo = manifestReturnTypeToDocument(member.returnType);
32404
- fields.argumentTypes = member.arguments.map((argument2) => ({
32405
- name: argument2.name,
32406
- ...manifestTypeToDocument(argument2.type)
32407
- }));
32982
+ fields.argumentTypes = member.arguments.map(manifestArgumentToDocument);
32408
32983
  fields.deferred = member.deferred;
32409
32984
  if (member.kind === "scriptFunction" && member.script !== null && member.bodyMode !== "ui") {
32410
32985
  fields.code = member.script.sourceText;
@@ -32416,16 +32991,10 @@ function memberToDocumentFields(member, baseData3) {
32416
32991
  }
32417
32992
  if (member.kind === "delegate") {
32418
32993
  fields.returnTypeInfo = manifestReturnTypeToDocument(member.returnType);
32419
- fields.argumentTypes = member.arguments.map((argument2) => ({
32420
- name: argument2.name,
32421
- ...manifestTypeToDocument(argument2.type)
32422
- }));
32994
+ fields.argumentTypes = member.arguments.map(manifestArgumentToDocument);
32423
32995
  }
32424
32996
  if (member.kind === "action") {
32425
- fields.argumentTypes = member.arguments.map((argument2) => ({
32426
- name: argument2.name,
32427
- ...manifestTypeToDocument(argument2.type)
32428
- }));
32997
+ fields.argumentTypes = member.arguments.map(manifestArgumentToDocument);
32429
32998
  }
32430
32999
  if (member.kind === "generic") {
32431
33000
  fields.genericParamId = member.genericParamId;
@@ -32515,11 +33084,25 @@ function documentArgumentsToManifest(value, record3, source) {
32515
33084
  `argumentTypes[${index}].name`
32516
33085
  ),
32517
33086
  type: documentTypeToManifest(argument2, record3, `argumentTypes[${index}]`),
33087
+ default: documentParameterDefaultToManifest(
33088
+ argument2.defaultValue,
33089
+ record3,
33090
+ `argumentTypes[${index}].defaultValue`,
33091
+ source
33092
+ ),
32518
33093
  source,
32519
33094
  selectionSpan: source
32520
33095
  };
32521
33096
  });
32522
33097
  }
33098
+ function documentParameterDefaultToManifest(value, record3, path, source) {
33099
+ if (value === void 0 || value === null) return null;
33100
+ const wrapper = requireRecordValue(value, record3, path);
33101
+ if (!Object.hasOwn(wrapper, "value")) {
33102
+ throw invalidDocument(record3, path, 'must carry a "value" key');
33103
+ }
33104
+ return { value: wrapper.value, source };
33105
+ }
32523
33106
  function optionalDocumentType(value, record3, path) {
32524
33107
  if (value === null || value === void 0) return null;
32525
33108
  return documentTypeToManifest(value, record3, path);
@@ -32668,6 +33251,13 @@ function documentTypeToManifest(value, record3, path) {
32668
33251
  `unsupported type-info discriminator ${kind}`
32669
33252
  );
32670
33253
  }
33254
+ function manifestArgumentToDocument(argument2) {
33255
+ return {
33256
+ name: argument2.name,
33257
+ ...manifestTypeToDocument(argument2.type),
33258
+ ...argument2.default === null ? {} : { defaultValue: { value: argument2.default.value } }
33259
+ };
33260
+ }
32671
33261
  function manifestReturnTypeToDocument(type) {
32672
33262
  if (type.kind === "void") return { type: "Void", required: true };
32673
33263
  return manifestTypeToDocument(type);
@@ -33407,10 +33997,7 @@ function interfaceToDocument(neoInterface) {
33407
33997
  kind: "function",
33408
33998
  ...member.docsText === void 0 ? {} : { docsText: member.docsText },
33409
33999
  returnTypeInfo: manifestReturnTypeToDocument(member.returnType),
33410
- argumentTypes: member.arguments.map((argument2) => ({
33411
- name: argument2.name,
33412
- ...manifestTypeToDocument(argument2.type)
33413
- })),
34000
+ argumentTypes: member.arguments.map(manifestArgumentToDocument),
33414
34001
  deferred: member.deferred,
33415
34002
  accessModifierKind: member.accessModifier
33416
34003
  };
@@ -33909,10 +34496,7 @@ function constructorToDocument(declared) {
33909
34496
  return omitUndefined({
33910
34497
  id: declared.id,
33911
34498
  classId: declared.classId,
33912
- argumentTypes: declared.arguments.map((argument2) => ({
33913
- name: argument2.name,
33914
- ...manifestTypeToDocument(argument2.type)
33915
- })),
34499
+ argumentTypes: declared.arguments.map(manifestArgumentToDocument),
33916
34500
  code: declared.code,
33917
34501
  baseArguments: declared.baseArguments,
33918
34502
  baseInitializerFields: declared.baseInitializerFields,
@@ -35568,14 +36152,22 @@ function assertFunctionArgument(value, path) {
35568
36152
  const argument2 = objectAt(value, path, [
35569
36153
  "name",
35570
36154
  "type",
36155
+ "default",
35571
36156
  "source",
35572
36157
  "selectionSpan"
35573
36158
  ]);
35574
36159
  nonEmptyString(argument2.name, `${path}.name`);
35575
36160
  assertType2(argument2.type, `${path}.type`);
36161
+ assertParameterDefault(argument2.default, `${path}.default`);
35576
36162
  assertSpan(argument2.source, `${path}.source`);
35577
36163
  assertSpan(argument2.selectionSpan, `${path}.selectionSpan`);
35578
36164
  }
36165
+ function assertParameterDefault(value, path) {
36166
+ if (value === null) return;
36167
+ const parameterDefault = objectAt(value, path, ["value", "source"]);
36168
+ assertJsonValue(parameterDefault.value, `${path}.value`, 0);
36169
+ assertSpan(parameterDefault.source, `${path}.source`);
36170
+ }
35579
36171
  function assertAbstractScriptInvariant(value, path) {
35580
36172
  const isAbstract = value.modifier === "abstract" || value.modifier === "abstractOverride";
35581
36173
  const hasUiBody = value.bodyMode === "ui" && value.uiAction !== void 0;
@@ -37789,7 +38381,30 @@ function isNSFunctionReturnTypeInfo(value) {
37789
38381
  return isNSTypeInfo(value) || isNSTypeInfoVoid(value);
37790
38382
  }
37791
38383
  function isNSFunctionArgumentTypeInfo(value) {
37792
- return isNSArgumentTypeInfo(value) && !typeInfoContainsUnknown(value, /* @__PURE__ */ new Set());
38384
+ return isNSArgumentTypeInfo(value) && !typeInfoContainsUnknown(value, /* @__PURE__ */ new Set()) && hasValidParameterDefault(value);
38385
+ }
38386
+ function hasValidParameterDefault(value) {
38387
+ const wrapper = value.defaultValue;
38388
+ if (wrapper === void 0) return true;
38389
+ if (typeof wrapper !== "object" || wrapper === null) return false;
38390
+ const keys = Object.keys(wrapper);
38391
+ if (keys.length !== 1 || keys[0] !== "value") return false;
38392
+ const payload = wrapper.value;
38393
+ if (payload === null) return !value.required;
38394
+ switch (value.type) {
38395
+ case 1 /* Bool */:
38396
+ return typeof payload === "boolean";
38397
+ case 2 /* Int */:
38398
+ return typeof payload === "number" && Number.isInteger(payload);
38399
+ case 4 /* Float */:
38400
+ return typeof payload === "number" && Number.isFinite(payload);
38401
+ case 20 /* Decimal */:
38402
+ case 3 /* String */:
38403
+ case 8 /* Enum */:
38404
+ return typeof payload === "string";
38405
+ default:
38406
+ return false;
38407
+ }
37793
38408
  }
37794
38409
  function typeInfoContainsUnknown(value, ancestors) {
37795
38410
  if (value.type === NS_TYPE_UNKNOWN) return true;
@@ -38590,6 +39205,51 @@ var init_neoscript_guards = __esm({
38590
39205
  }
38591
39206
  });
38592
39207
 
39208
+ // ../src/models/neoscript/parameter-defaults.ts
39209
+ function parameterHasDefault(argument2) {
39210
+ return argument2.defaultValue !== void 0;
39211
+ }
39212
+ function hasAnyParameterDefault(argumentTypes) {
39213
+ return argumentTypes.some(parameterHasDefault);
39214
+ }
39215
+ function validateParameterDefaults(argumentTypes) {
39216
+ const violations = [];
39217
+ let lastNonDefaultedIndex = -1;
39218
+ for (let index = argumentTypes.length - 1; index >= 0; index -= 1) {
39219
+ const argument2 = argumentTypes[index];
39220
+ if (argument2 !== void 0 && !parameterHasDefault(argument2)) {
39221
+ lastNonDefaultedIndex = index;
39222
+ break;
39223
+ }
39224
+ }
39225
+ for (let index = 0; index < argumentTypes.length; index += 1) {
39226
+ const argument2 = argumentTypes[index];
39227
+ if (argument2 === void 0) continue;
39228
+ const defaultValue = argument2.defaultValue;
39229
+ if (defaultValue === void 0) continue;
39230
+ if (index < lastNonDefaultedIndex) {
39231
+ violations.push({
39232
+ code: "default-before-required-parameter",
39233
+ index,
39234
+ name: argument2.name
39235
+ });
39236
+ }
39237
+ if (defaultValue.value === null && argument2.required) {
39238
+ violations.push({
39239
+ code: "parameter-default-type-mismatch",
39240
+ index,
39241
+ name: argument2.name
39242
+ });
39243
+ }
39244
+ }
39245
+ return violations;
39246
+ }
39247
+ var init_parameter_defaults = __esm({
39248
+ "../src/models/neoscript/parameter-defaults.ts"() {
39249
+ "use strict";
39250
+ }
39251
+ });
39252
+
38593
39253
  // ../src/models/interfaces/interface-graph.ts
38594
39254
  function resolveInterfaceClosure(interfaceId, interfaces) {
38595
39255
  const byId = new Map(
@@ -38726,6 +39386,7 @@ var init_neoscript = __esm({
38726
39386
  "use strict";
38727
39387
  init_neoscript_types();
38728
39388
  init_neoscript_guards();
39389
+ init_parameter_defaults();
38729
39390
  init_type_info_compatibility();
38730
39391
  }
38731
39392
  });
@@ -39384,14 +40045,20 @@ function isMemberFunctionBase(value) {
39384
40045
  if (!Array.isArray(v.argumentTypes)) return false;
39385
40046
  if (typeof v.deferred !== "boolean") return false;
39386
40047
  const names = /* @__PURE__ */ new Set();
40048
+ const argumentTypes = [];
39387
40049
  for (const arg of v.argumentTypes) {
39388
40050
  if (!isNSFunctionArgumentTypeInfo(arg)) return false;
39389
40051
  if (!isValidCallableIdentifier(arg.name)) return false;
39390
40052
  if (arg.type === NS_TYPE_UNKNOWN) return false;
39391
40053
  if (names.has(arg.name)) return false;
39392
40054
  names.add(arg.name);
40055
+ argumentTypes.push(arg);
39393
40056
  }
39394
- return true;
40057
+ return hasValidParameterDefaults(argumentTypes, v.deferred);
40058
+ }
40059
+ function hasValidParameterDefaults(argumentTypes, deferred) {
40060
+ if (deferred && hasAnyParameterDefault(argumentTypes)) return false;
40061
+ return validateParameterDefaults(argumentTypes).length === 0;
39395
40062
  }
39396
40063
  function normalizedCompiledFunctionReturnType(typeInfo) {
39397
40064
  if (typeInfo.type === NS_TYPE_VOID) {
@@ -39439,6 +40106,7 @@ function isMemberNSFunctionBase(value) {
39439
40106
  if (v.action !== void 0 && v.action !== null) return false;
39440
40107
  if (v.bodyMode !== void 0 && v.bodyMode !== "ui") return false;
39441
40108
  const names = /* @__PURE__ */ new Set();
40109
+ const argumentTypes = [];
39442
40110
  for (const argument2 of v.argumentTypes) {
39443
40111
  if (!isNSFunctionArgumentTypeInfo(argument2)) return false;
39444
40112
  if (argument2.type === NS_TYPE_UNKNOWN) return false;
@@ -39446,7 +40114,9 @@ function isMemberNSFunctionBase(value) {
39446
40114
  if (NSFunctionArgumentReservedNames.has(argument2.name)) return false;
39447
40115
  if (names.has(argument2.name)) return false;
39448
40116
  names.add(argument2.name);
40117
+ argumentTypes.push(argument2);
39449
40118
  }
40119
+ if (!hasValidParameterDefaults(argumentTypes, v.deferred)) return false;
39450
40120
  if (v.isAbstract === true) {
39451
40121
  if (v.bodyMode !== void 0) return false;
39452
40122
  if (v.uiAction !== void 0 && v.uiAction !== null) return false;
@@ -39523,6 +40193,7 @@ function isMemberDelegateBase(value) {
39523
40193
  if (argument2.type === NS_TYPE_UNKNOWN) return false;
39524
40194
  if (names.has(argument2.name)) return false;
39525
40195
  names.add(argument2.name);
40196
+ if (argument2.defaultValue !== void 0) return false;
39526
40197
  }
39527
40198
  const defaultValue = v.defaultValue;
39528
40199
  if (defaultValue === void 0 || defaultValue === null) return true;
@@ -39561,6 +40232,7 @@ function isMemberActionBase(value) {
39561
40232
  if (argument2.type === NS_TYPE_UNKNOWN) return false;
39562
40233
  if (names.has(argument2.name)) return false;
39563
40234
  names.add(argument2.name);
40235
+ if (argument2.defaultValue !== void 0) return false;
39564
40236
  }
39565
40237
  const defaultValue = v.defaultValue;
39566
40238
  if (defaultValue === void 0 || defaultValue === null) return true;
@@ -39792,6 +40464,7 @@ function isMemberOverrideBase(value) {
39792
40464
  if (v.argumentTypes !== void 0) {
39793
40465
  if (!Array.isArray(v.argumentTypes)) return false;
39794
40466
  if (!v.argumentTypes.every(isNSFunctionArgumentTypeInfo)) return false;
40467
+ if (hasAnyParameterDefault(v.argumentTypes)) return false;
39795
40468
  }
39796
40469
  if (v.deferred !== void 0 && typeof v.deferred !== "boolean") {
39797
40470
  return false;
@@ -43670,7 +44343,11 @@ function isNeoInterfaceMember(value) {
43670
44343
  if (!isNSFunctionArgumentTypeInfo(argumentType)) return false;
43671
44344
  if (containsForbiddenMemberTypeInfo(argumentType)) return false;
43672
44345
  }
43673
- return typeof member.deferred === "boolean";
44346
+ if (typeof member.deferred !== "boolean") return false;
44347
+ if (member.deferred && hasAnyParameterDefault(member.argumentTypes)) {
44348
+ return false;
44349
+ }
44350
+ return validateParameterDefaults(member.argumentTypes).length === 0;
43674
44351
  }
43675
44352
  function isInterfaceMembersRecord(value) {
43676
44353
  if (typeof value !== "object") return false;
@@ -43738,6 +44415,7 @@ var init_interface_types = __esm({
43738
44415
  init_neoscript_types();
43739
44416
  init_docs_text2();
43740
44417
  init_neoscript_guards();
44418
+ init_parameter_defaults();
43741
44419
  init_member_kinds();
43742
44420
  }
43743
44421
  });
@@ -46056,11 +46734,46 @@ function baseConstruction(requiredConstructor) {
46056
46734
  function renderHeaderParameters(context, requiredConstructor) {
46057
46735
  if (requiredConstructor === void 0) return "";
46058
46736
  const parameters = requiredConstructor.arguments.map(
46059
- (argument2) => `${renderType(context, argument2.type)} ${argument2.name}`
46737
+ (argument2) => renderParameter(context, argument2)
46060
46738
  );
46061
46739
  if (parameters.length === 0 && requiredConstructor.code !== null) return "";
46062
46740
  return `(${parameters.join(", ")})`;
46063
46741
  }
46742
+ function renderParameter(context, argument2) {
46743
+ const declaration = `${renderType(context, argument2.type)} ${argument2.name}`;
46744
+ if (argument2.default === null) return declaration;
46745
+ return `${declaration} = ${renderParameterDefault(context, argument2)}`;
46746
+ }
46747
+ function renderParameterDefault(context, argument2) {
46748
+ const value = argument2.default?.value;
46749
+ if (value === null || value === void 0) return "null";
46750
+ if (argument2.type.kind === "enum") {
46751
+ if (typeof value !== "string") {
46752
+ throw new Error(
46753
+ `Parameter ${argument2.name} stores an enum default that is not an option id.`
46754
+ );
46755
+ }
46756
+ const schemaEnum = required(context.enums, argument2.type.enumId, "enum");
46757
+ const option = schemaEnum.options.find(
46758
+ (candidate) => candidate.id === value || candidate.key === value
46759
+ );
46760
+ if (option === void 0) {
46761
+ throw new Error(
46762
+ `Parameter ${argument2.name} defaults to option id ${quote(value)}, which its enum does not declare. Emitting it as null would delete the default on the next push.`
46763
+ );
46764
+ }
46765
+ return `.${option.name}`;
46766
+ }
46767
+ if (argument2.type.kind === "decimal" && typeof value === "string") {
46768
+ return value;
46769
+ }
46770
+ if (typeof value === "string") return quote(value);
46771
+ if (typeof value === "number") return formatNeoNumber(value);
46772
+ if (typeof value === "boolean") return String(value);
46773
+ throw new Error(
46774
+ `Parameter ${argument2.name} stores a default that is not a constant value.`
46775
+ );
46776
+ }
46064
46777
  function emitInitBlock(code) {
46065
46778
  if (code.trim().length === 0) return "init {\n}";
46066
46779
  return `init {
@@ -46075,7 +46788,7 @@ function emitConstructor(context, schemaClass2, declared) {
46075
46788
  ...docsTextLines(declared.docsText),
46076
46789
  id(declared.id).trimEnd()
46077
46790
  ];
46078
- const parameters = declared.arguments.map((argument2) => `${renderType(context, argument2.type)} ${argument2.name}`).join(", ");
46791
+ const parameters = declared.arguments.map((argument2) => renderParameter(context, argument2)).join(", ");
46079
46792
  const baseClause = declared.baseArguments === void 0 || declared.baseArguments.length === 0 ? "" : `
46080
46793
  : base(${declared.baseArguments.map((argument2) => `${argument2.name}: ${argument2.code}`).join(", ")})`;
46081
46794
  const code = declared.code ?? "";
@@ -46145,9 +46858,7 @@ function emitInterface(context, value) {
46145
46858
  return `${emitDocsText(member.docsText)}${id(member.id)}${access}${renderType(context, member.type)} ${member.name} { get;${member.settable ? " set;" : ""} }`;
46146
46859
  }
46147
46860
  const deferred = member.deferred ? "async " : "";
46148
- return `${emitDocsText(member.docsText)}${id(member.id)}${access}${deferred}${renderReturnType(context, member.returnType)} ${member.name}(${member.arguments.map(
46149
- (argument2) => `${renderType(context, argument2.type)} ${argument2.name}`
46150
- ).join(", ")});`;
46861
+ return `${emitDocsText(member.docsText)}${id(member.id)}${access}${deferred}${renderReturnType(context, member.returnType)} ${member.name}(${member.arguments.map((argument2) => renderParameter(context, argument2)).join(", ")});`;
46151
46862
  });
46152
46863
  return `${emitDocsText(value.docsText)}${id(value.id)}interface ${value.name}${bases.length ? ` : ${bases.join(", ")}` : ""} {
46153
46864
  ${members.map((member) => indentNeoSourceNonEmptyLines(member, 2)).join("\n\n")}
@@ -46195,9 +46906,7 @@ ${indentNeoSourceNonEmptyLines(setter, 4)}
46195
46906
  ${prefix}${renderType(context, member.returnType)} ${member.name}${body}`;
46196
46907
  }
46197
46908
  if (member.kind === "function" || member.kind === "scriptFunction") {
46198
- const signature = `${prefix}${member.deferred ? "async " : ""}${renderReturnType(context, member.returnType)} ${member.name}(${member.arguments.map(
46199
- (argument2) => `${renderType(context, argument2.type)} ${argument2.name}`
46200
- ).join(", ")})`;
46909
+ const signature = `${prefix}${member.deferred ? "async " : ""}${renderReturnType(context, member.returnType)} ${member.name}(${member.arguments.map((argument2) => renderParameter(context, argument2)).join(", ")})`;
46201
46910
  const tracked = member.kind === "scriptFunction" ? member.script?.sourceText ?? uiFunctionSource(context, member) : null;
46202
46911
  const body = tracked === null ? null : emitFunctionBody(tracked);
46203
46912
  const abstractContract = member.modifier === "abstract" || member.modifier === "abstractOverride";
@@ -51280,13 +51989,13 @@ function withPersistedConstructorSignatures(index, classes, constructors) {
51280
51989
  if (required2 !== void 0) {
51281
51990
  persistedRequiredByClassName.set(
51282
51991
  schemaClass2.name,
51283
- required2.arguments.map((argument2) => argument2.name)
51992
+ required2.arguments.map(persistedParameter)
51284
51993
  );
51285
51994
  }
51286
51995
  }
51287
51996
  const overloads = (schemaClass2.constructorIds ?? []).flatMap((id2) => {
51288
51997
  const constructor2 = byId.get(id2);
51289
- return constructor2 === void 0 ? [] : [constructor2.arguments.map((argument2) => argument2.name)];
51998
+ return constructor2 === void 0 ? [] : [constructor2.arguments.map(persistedParameter)];
51290
51999
  });
51291
52000
  if (overloads.length > 0) {
51292
52001
  persistedByClassName.set(schemaClass2.name, overloads);
@@ -51298,6 +52007,10 @@ function withPersistedConstructorSignatures(index, classes, constructors) {
51298
52007
  persistedRequiredByClassName
51299
52008
  };
51300
52009
  }
52010
+ function persistedParameter(argument2) {
52011
+ const hasDefault = argument2.default !== null && argument2.default !== void 0;
52012
+ return { name: argument2.name, defaulted: hasDefault };
52013
+ }
51301
52014
  function declaresConstructors(index, className) {
51302
52015
  if (className === null) return false;
51303
52016
  if (index.requiredByClassName.has(className)) return true;
@@ -51307,16 +52020,24 @@ function declaresConstructors(index, className) {
51307
52020
  function declaresParameterlessConstructor(index, className) {
51308
52021
  if (className === null) return false;
51309
52022
  const required2 = index.requiredByClassName.get(className);
51310
- if (required2 !== void 0 && required2.parameters.length === 0) return true;
52023
+ if (required2 !== void 0 && manifestListIsCallableBare(required2.parameters)) {
52024
+ return true;
52025
+ }
51311
52026
  const persistedRequired = index.persistedRequiredByClassName.get(className);
51312
- if (persistedRequired !== void 0 && persistedRequired.length === 0) {
52027
+ if (persistedRequired !== void 0 && persistedListIsCallableBare(persistedRequired)) {
51313
52028
  return true;
51314
52029
  }
51315
52030
  const declared = index.byClassName.get(className);
51316
- if (declared?.some((entry) => entry.parameters.length === 0) === true) {
52031
+ if (declared?.some((entry) => manifestListIsCallableBare(entry.parameters)) === true) {
51317
52032
  return true;
51318
52033
  }
51319
- return index.persistedByClassName.get(className)?.some((parameters) => parameters.length === 0) ?? false;
52034
+ return index.persistedByClassName.get(className)?.some(persistedListIsCallableBare) ?? false;
52035
+ }
52036
+ function manifestListIsCallableBare(parameters) {
52037
+ return parameters.every((parameter4) => parameter4.default !== null);
52038
+ }
52039
+ function persistedListIsCallableBare(parameters) {
52040
+ return parameters.every((parameter4) => parameter4.defaulted);
51320
52041
  }
51321
52042
  function initializerRequiresEvaluation(index, expression, targetClassName, runtimeIdentifiers = /* @__PURE__ */ new Set()) {
51322
52043
  if (expression.kind === "annotated") {
@@ -51346,7 +52067,11 @@ function requiredConstructorParameterNames(index, className) {
51346
52067
  if (required2 !== void 0) {
51347
52068
  return new Set(required2.parameters.map((parameter4) => parameter4.name));
51348
52069
  }
51349
- return new Set(index.persistedRequiredByClassName.get(className) ?? []);
52070
+ return new Set(
52071
+ (index.persistedRequiredByClassName.get(className) ?? []).map(
52072
+ (parameter4) => parameter4.name
52073
+ )
52074
+ );
51350
52075
  }
51351
52076
  function expressionReadsRuntimeIdentifier(expression, runtimeIdentifiers) {
51352
52077
  if (runtimeIdentifiers.size === 0) return false;
@@ -51438,7 +52163,8 @@ function validateDeclaredConstructorOverloads(declaration) {
51438
52163
  id: declared.id ?? `${declaration.name}#${String(index)}`,
51439
52164
  parameters: declared.parameters.map((parameter4) => ({
51440
52165
  name: parameter4.name,
51441
- typeKey: positionalTypeKey(parameter4.type)
52166
+ typeKey: positionalTypeKey(parameter4.type),
52167
+ defaulted: parameter4.default !== null
51442
52168
  }))
51443
52169
  }))
51444
52170
  ).map((error) => ({
@@ -51464,6 +52190,102 @@ var init_declared_constructors2 = __esm({
51464
52190
  }
51465
52191
  });
51466
52192
 
52193
+ // src/project-source/lower-parameter-defaults.ts
52194
+ function lowerParameterDefault(context, parameter4, loweredType, path) {
52195
+ if (parameter4.default === null) return null;
52196
+ const expression = parseExpression(parameter4.default);
52197
+ return {
52198
+ value: lowerParameterDefaultValue(context, expression, loweredType, path),
52199
+ source: span({ source: parameter4.source })
52200
+ };
52201
+ }
52202
+ function lowerParameterDefaultValue(context, expression, type, path) {
52203
+ switch (expression.kind) {
52204
+ case "litNull":
52205
+ if (!type.nullable) {
52206
+ throw new Error(
52207
+ `Parameter ${path} defaults to null, but its type is not nullable.`
52208
+ );
52209
+ }
52210
+ return null;
52211
+ case "litBool":
52212
+ if (type.kind !== "bool") {
52213
+ throw new Error(
52214
+ `Parameter ${path} defaults to a bool literal, but its type is ${type.kind}.`
52215
+ );
52216
+ }
52217
+ return expression.value;
52218
+ case "litString":
52219
+ if (type.kind !== "string") {
52220
+ throw new Error(
52221
+ `Parameter ${path} defaults to a string literal, but its type is ${type.kind}.`
52222
+ );
52223
+ }
52224
+ return expression.value;
52225
+ case "litInt":
52226
+ if (type.kind === "decimal") return expression.raw;
52227
+ if (type.kind !== "int" && type.kind !== "float") {
52228
+ throw new Error(
52229
+ `Parameter ${path} defaults to a number literal, but its type is ${type.kind}.`
52230
+ );
52231
+ }
52232
+ return expression.value;
52233
+ case "litFloat":
52234
+ if (type.kind === "decimal") return expression.raw;
52235
+ if (type.kind !== "float") {
52236
+ throw new Error(
52237
+ `Parameter ${path} defaults to a fractional literal, but its type is ${type.kind}.`
52238
+ );
52239
+ }
52240
+ return expression.value;
52241
+ case "unary": {
52242
+ if (expression.op !== "-") {
52243
+ throw new Error(
52244
+ `Parameter ${path} default uses unary ${JSON.stringify(expression.op)}, which is not a constant spelling.`
52245
+ );
52246
+ }
52247
+ const operand = lowerParameterDefaultValue(
52248
+ context,
52249
+ expression.operand,
52250
+ type,
52251
+ path
52252
+ );
52253
+ if (typeof operand === "number") return -operand;
52254
+ if (type.kind === "decimal" && typeof operand === "string") {
52255
+ return operand.startsWith("-") ? operand.slice(1) : `-${operand}`;
52256
+ }
52257
+ throw new Error(
52258
+ `Parameter ${path} default applies unary minus to a non-numeric literal.`
52259
+ );
52260
+ }
52261
+ case "contextualEnum": {
52262
+ if (type.kind !== "enum") {
52263
+ throw new Error(
52264
+ `Parameter ${path} defaults to enum option .${expression.name}, but its type is ${type.kind}.`
52265
+ );
52266
+ }
52267
+ const optionId = context.enumOptionsByName.get(type.enumId)?.get(expression.name);
52268
+ if (optionId === void 0) {
52269
+ throw new Error(
52270
+ `Parameter ${path} defaults to .${expression.name}, which its enum does not declare.`
52271
+ );
52272
+ }
52273
+ return optionId;
52274
+ }
52275
+ default:
52276
+ throw new Error(
52277
+ `Parameter ${path} default is not a constant expression.`
52278
+ );
52279
+ }
52280
+ }
52281
+ var init_lower_parameter_defaults = __esm({
52282
+ "src/project-source/lower-parameter-defaults.ts"() {
52283
+ "use strict";
52284
+ init_src();
52285
+ init_lower_support();
52286
+ }
52287
+ });
52288
+
51467
52289
  // src/project-source/init-source.ts
51468
52290
  function commentEndIndex(source, index) {
51469
52291
  if (source[index] !== "/") return null;
@@ -51700,12 +52522,21 @@ function lowerClassConstructors(context, declaration, classId, lowerParameterTyp
51700
52522
  const declared = declaration.constructors.map((declared2) => {
51701
52523
  const id2 = declaredConstructorId2(declaration, declared2);
51702
52524
  const base = context.baseConstructors.get(id2);
51703
- const parameters = declared2.parameters.map((parameter4) => ({
51704
- name: parameter4.name,
51705
- type: lowerParameterType(parameter4.type, declaration),
51706
- source: span({ source: parameter4.source }),
51707
- selectionSpan: span({ source: parameter4.source })
51708
- }));
52525
+ const parameters = declared2.parameters.map((parameter4) => {
52526
+ const parameterType = lowerParameterType(parameter4.type, declaration);
52527
+ return {
52528
+ name: parameter4.name,
52529
+ type: parameterType,
52530
+ default: lowerParameterDefault(
52531
+ context,
52532
+ parameter4,
52533
+ parameterType,
52534
+ `${declaration.name}.${declared2.name}(${parameter4.name})`
52535
+ ),
52536
+ source: span({ source: parameter4.source }),
52537
+ selectionSpan: span({ source: parameter4.source })
52538
+ };
52539
+ });
51709
52540
  const baseArguments = (declared2.baseArguments ?? []).map((argument2) => ({
51710
52541
  name: argument2.name,
51711
52542
  code: argument2.expression.trim()
@@ -51746,12 +52577,21 @@ function lowerRequiredConstructor(context, declaration, classId, lowerParameterT
51746
52577
  selectionSpan: sourceSpan
51747
52578
  },
51748
52579
  classId,
51749
- arguments: required2.parameters.map((parameter4) => ({
51750
- name: parameter4.name,
51751
- type: lowerParameterType(parameter4.type, declaration),
51752
- source: span({ source: parameter4.source }),
51753
- selectionSpan: span({ source: parameter4.source })
51754
- })),
52580
+ arguments: required2.parameters.map((parameter4) => {
52581
+ const parameterType = lowerParameterType(parameter4.type, declaration);
52582
+ return {
52583
+ name: parameter4.name,
52584
+ type: parameterType,
52585
+ default: lowerParameterDefault(
52586
+ context,
52587
+ parameter4,
52588
+ parameterType,
52589
+ `${declaration.name}(${parameter4.name})`
52590
+ ),
52591
+ source: span({ source: parameter4.source }),
52592
+ selectionSpan: span({ source: parameter4.source })
52593
+ };
52594
+ }),
51755
52595
  code: requiredConstructorBody(required2.body, base?.code),
51756
52596
  ...baseArguments.length === 0 ? {} : {
51757
52597
  baseArguments: baseArguments.map(
@@ -51834,10 +52674,10 @@ function recordBaseParameterNames(context, baseName, suppliedNames) {
51834
52674
  function selectOverload(candidates, suppliedNames) {
51835
52675
  if (candidates.length === 0) return null;
51836
52676
  if (candidates.length === 1) return candidates[0];
51837
- const key = argumentNameSetKey2(suppliedNames);
51838
- return candidates.find((names) => argumentNameSetKey2(names) === key) ?? null;
52677
+ const key = argumentNameSetKey(suppliedNames);
52678
+ return candidates.find((names) => argumentNameSetKey(names) === key) ?? null;
51839
52679
  }
51840
- function argumentNameSetKey2(names) {
52680
+ function argumentNameSetKey(names) {
51841
52681
  return [...names].map((name) => name.toLowerCase()).sort().join(",");
51842
52682
  }
51843
52683
  function baseTypeName(declaration) {
@@ -51876,6 +52716,7 @@ var init_lower_constructors = __esm({
51876
52716
  init_src();
51877
52717
  init_required_constructor_id();
51878
52718
  init_declared_constructors2();
52719
+ init_lower_parameter_defaults();
51879
52720
  init_init_source();
51880
52721
  init_lower_support();
51881
52722
  }
@@ -52223,12 +53064,21 @@ function lowerMemberKind(context, ownerClass, declaration, id2, owner) {
52223
53064
  if (declaration.kind === "function") {
52224
53065
  const returnType = declaration.type.name === "void" ? { kind: "void", nullable: false } : lowerType(context, declaration.type, ownerClass);
52225
53066
  const argumentsValue = declaration.parameters.map(
52226
- (parameter4) => ({
52227
- name: parameter4.name,
52228
- type: lowerType(context, parameter4.type, ownerClass),
52229
- source: span(parameter4),
52230
- selectionSpan: span(parameter4)
52231
- })
53067
+ (parameter4) => {
53068
+ const parameterType = lowerType(context, parameter4.type, ownerClass);
53069
+ return {
53070
+ name: parameter4.name,
53071
+ type: parameterType,
53072
+ default: lowerParameterDefault(
53073
+ context,
53074
+ parameter4,
53075
+ parameterType,
53076
+ `${ownerClass.name}.${declaration.name}(${parameter4.name})`
53077
+ ),
53078
+ source: span(parameter4),
53079
+ selectionSpan: span(parameter4)
53080
+ };
53081
+ }
52232
53082
  );
52233
53083
  const settings = annotation(declaration.annotations, "settings");
52234
53084
  const logicMode = contextualEnumArgument(settings, "logic");
@@ -52458,6 +53308,7 @@ function lowerFieldMember(context, ownerClass, declaration, id2, commonInput, ba
52458
53308
  arguments: fieldType.arguments.slice(1).map((argumentType, index) => ({
52459
53309
  name: `p${index + 1}`,
52460
53310
  type: lowerType(context, argumentType, ownerClass),
53311
+ default: null,
52461
53312
  source: span(declaration),
52462
53313
  selectionSpan: span(declaration)
52463
53314
  }))
@@ -52482,6 +53333,7 @@ function lowerFieldMember(context, ownerClass, declaration, id2, commonInput, ba
52482
53333
  arguments: fieldType.arguments.map((argumentType, index) => ({
52483
53334
  name: `p${index + 1}`,
52484
53335
  type: lowerType(context, argumentType, ownerClass),
53336
+ default: null,
52485
53337
  source: span(declaration),
52486
53338
  selectionSpan: span(declaration)
52487
53339
  }))
@@ -52941,12 +53793,21 @@ function lowerInterface(context, declaration) {
52941
53793
  name: member.name,
52942
53794
  ...member.docsText === void 0 ? {} : { docsText: member.docsText },
52943
53795
  returnType: member.type.name === "void" ? { kind: "void", nullable: false } : lowerType(context, member.type),
52944
- arguments: member.parameters.map((parameter4) => ({
52945
- name: parameter4.name,
52946
- type: lowerType(context, parameter4.type),
52947
- source: span(parameter4),
52948
- selectionSpan: span(parameter4)
52949
- })),
53796
+ arguments: member.parameters.map((parameter4) => {
53797
+ const parameterType = lowerType(context, parameter4.type);
53798
+ return {
53799
+ name: parameter4.name,
53800
+ type: parameterType,
53801
+ default: lowerParameterDefault(
53802
+ context,
53803
+ parameter4,
53804
+ parameterType,
53805
+ `${declaration.name}.${member.name}(${parameter4.name})`
53806
+ ),
53807
+ source: span(parameter4),
53808
+ selectionSpan: span(parameter4)
53809
+ };
53810
+ }),
52950
53811
  deferred: member.modifiers.includes("async"),
52951
53812
  accessModifier,
52952
53813
  source
@@ -54264,6 +55125,7 @@ var init_lower_members = __esm({
54264
55125
  init_src();
54265
55126
  init_lower_support();
54266
55127
  init_lower_constructors();
55128
+ init_lower_parameter_defaults();
54267
55129
  init_declared_constructors2();
54268
55130
  init_init_source();
54269
55131
  init_ui_action_source();
@@ -54399,7 +55261,8 @@ function createNeoScriptDocumentContext(context, projectOverride) {
54399
55261
  const parameters = context.functionArguments?.map((argument2, index) => ({
54400
55262
  id: `function-parameter:${index}:${argument2.name}`,
54401
55263
  name: argument2.name,
54402
- type: toLanguageType(argument2, context)
55264
+ type: toLanguageType(argument2, context),
55265
+ ...parameterDefaultDescriptor(argument2, context)
54403
55266
  }));
54404
55267
  return {
54405
55268
  kind: documentKind,
@@ -54421,6 +55284,32 @@ function createNeoScriptDocumentContext(context, projectOverride) {
54421
55284
  } : {}
54422
55285
  };
54423
55286
  }
55287
+ function parameterDefaultDescriptor(argument2, context) {
55288
+ if (argument2.defaultValue === void 0) return {};
55289
+ const value = argument2.defaultValue.value;
55290
+ const enumOptionName = argument2.type === 8 /* Enum */ && typeof value === "string" ? analyzerEnumOptionName(argument2.enumId, value, context) : void 0;
55291
+ return {
55292
+ defaultValue: {
55293
+ displayText: neoScriptParameterDefaultDisplayText({
55294
+ value,
55295
+ kind: parameterDefaultSpellingKind(argument2.type),
55296
+ ...enumOptionName === void 0 ? {} : { enumOptionName }
55297
+ }),
55298
+ value
55299
+ }
55300
+ };
55301
+ }
55302
+ function parameterDefaultSpellingKind(type) {
55303
+ if (type === 8 /* Enum */) return "enum";
55304
+ if (type === 20 /* Decimal */) return "decimal";
55305
+ return "other";
55306
+ }
55307
+ function analyzerEnumOptionName(enumId, optionId, context) {
55308
+ const enumDefinition = context.vm.enums.find(
55309
+ (candidate) => candidate.id === enumId
55310
+ );
55311
+ return enumDefinition?.options[optionId]?.name;
55312
+ }
54424
55313
  function createNeoScriptProject(context) {
54425
55314
  const languageTypes = [];
54426
55315
  for (const schemaClass2 of context.vm.classes) {
@@ -54708,7 +55597,8 @@ function declaredConstructors(schemaClass2, context) {
54708
55597
  parameters: record3.argumentTypes.map((argument2) => ({
54709
55598
  name: argument2.name,
54710
55599
  type: toLanguageType(argument2, context),
54711
- required: argument2.required
55600
+ required: argument2.required,
55601
+ ...parameterDefaultDescriptor(argument2, context)
54712
55602
  })),
54713
55603
  ...record3.docsText ? { documentation: record3.docsText } : {},
54714
55604
  ...record3.id === required2 ? { required: true } : {}
@@ -54784,7 +55674,8 @@ function memberToSymbol(record3, schemaKey, containingClass2, ownerClassId, inde
54784
55674
  (argument2, argumentIndex) => ({
54785
55675
  id: `${record3.id}:argument:${argumentIndex}`,
54786
55676
  name: argument2.name,
54787
- type: toLanguageType(argument2, context, genericEnvironment)
55677
+ type: toLanguageType(argument2, context, genericEnvironment),
55678
+ ...parameterDefaultDescriptor(argument2, context)
54788
55679
  })
54789
55680
  ),
54790
55681
  deferred: authoredCallable.deferred,
@@ -54955,7 +55846,8 @@ function interfaceMemberToSymbol(neoInterface, key, member, context, inherited)
54955
55846
  parameters: member.argumentTypes.map((argument2, index) => ({
54956
55847
  id: `${neoInterface.id}:member:${key}:argument:${index}`,
54957
55848
  name: argument2.name,
54958
- type: toLanguageType(argument2, context)
55849
+ type: toLanguageType(argument2, context),
55850
+ ...parameterDefaultDescriptor(argument2, context)
54959
55851
  })),
54960
55852
  deferred: member.deferred,
54961
55853
  abstract: true,
@@ -56535,13 +57427,13 @@ function resolveBaseConstructorOverload(args, owner) {
56535
57427
  `Constructor "${args.constructor.id}" declares a base call, but base class "${baseClass.name}" declares no constructors.`
56536
57428
  );
56537
57429
  }
56538
- const requested = argumentNameSetKey3(
57430
+ const requested = argumentNameSetKey2(
56539
57431
  (args.constructor.baseArguments ?? []).map(
56540
57432
  (baseArgument) => baseArgument.name
56541
57433
  )
56542
57434
  );
56543
57435
  const matches = candidates.filter(
56544
- (candidate) => argumentNameSetKey3(
57436
+ (candidate) => argumentNameSetKey2(
56545
57437
  candidate.argumentTypes.map((argument2) => argument2.name)
56546
57438
  ) === requested
56547
57439
  );
@@ -56597,7 +57489,7 @@ function declaredConstructorsOfClass(constructors, schemaClass2) {
56597
57489
  return [record3];
56598
57490
  });
56599
57491
  }
56600
- function argumentNameSetKey3(names) {
57492
+ function argumentNameSetKey2(names) {
56601
57493
  return [...names].map((name) => name.toLowerCase()).sort().join(", ");
56602
57494
  }
56603
57495
  function describeConstructorOverloads(constructors) {
@@ -59911,16 +60803,21 @@ function executeCompiledFunction(action, ctx, args, allowFallthroughReturn, runt
59911
60803
  `Corrupt NSFunction IR: compiled body has ${action.parameters.length - 2} argument parameter(s), but its runtime signature declares ${expectedCount}.`
59912
60804
  );
59913
60805
  }
59914
- if (args.length !== expectedCount) {
60806
+ const filledArgs = runtimeSignature === void 0 ? args : fillTrailingParameterDefaults(
60807
+ args,
60808
+ runtimeSignature.argumentTypes,
60809
+ "NSFunction"
60810
+ );
60811
+ if (filledArgs.length !== expectedCount) {
59915
60812
  throw new NSGetterRuntimeError(
59916
- `NSFunction expected ${expectedCount} argument(s), got ${args.length}.`
60813
+ `NSFunction expected ${expectedCount} argument(s), got ${filledArgs.length}.`
59917
60814
  );
59918
60815
  }
59919
60816
  const scope = createTopLevelScope(ctx);
59920
- for (let index = 0; index < args.length; index += 1) {
60817
+ for (let index = 0; index < filledArgs.length; index += 1) {
59921
60818
  const parameter4 = action.parameters[index + 2];
59922
60819
  const runtimeTypeInfo = runtimeArgumentTypes[index];
59923
- const value2 = args[index];
60820
+ const value2 = filledArgs[index];
59924
60821
  if (!runtimeValueMatchesType(value2, runtimeTypeInfo, ctx)) {
59925
60822
  throw new NSGetterRuntimeError(
59926
60823
  `NSFunction argument ${index + 1} does not match its declared runtime type.`
@@ -59961,6 +60858,57 @@ function executeCompiledFunction(action, ctx, args, allowFallthroughReturn, runt
59961
60858
  }
59962
60859
  return value;
59963
60860
  }
60861
+ function fillTrailingParameterDefaults(args, argumentTypes, subject) {
60862
+ const maxArity = argumentTypes.length;
60863
+ const minArity = argumentTypes.filter(
60864
+ (parameter4) => !parameterHasDefault(parameter4)
60865
+ ).length;
60866
+ const expectedArity = minArity === maxArity ? `${maxArity} argument(s)` : `between ${minArity} and ${maxArity} argument(s)`;
60867
+ if (args.length > maxArity) {
60868
+ throw new NSGetterRuntimeError(
60869
+ `${subject} expected ${expectedArity}, got ${args.length}.`
60870
+ );
60871
+ }
60872
+ if (args.length < minArity) {
60873
+ throw new NSGetterRuntimeError(
60874
+ `${subject} expected ${expectedArity}, got ${args.length}.`
60875
+ );
60876
+ }
60877
+ if (args.length === maxArity) return args;
60878
+ const filled = [...args];
60879
+ for (let index = args.length; index < maxArity; index += 1) {
60880
+ const parameter4 = argumentTypes[index];
60881
+ if (parameter4 === void 0) {
60882
+ throw new NSGetterRuntimeError(
60883
+ `${subject} has a hole in its argument types at position ${index}.`
60884
+ );
60885
+ }
60886
+ filled.push(parameterDefaultRuntimeValue(parameter4, subject));
60887
+ }
60888
+ return filled;
60889
+ }
60890
+ function parameterDefaultRuntimeValue(parameter4, subject) {
60891
+ const defaultValue = parameter4.defaultValue;
60892
+ if (defaultValue === void 0) {
60893
+ throw new NSGetterRuntimeError(
60894
+ `${subject} parameter '${parameter4.name}' was omitted but declares no default.`
60895
+ );
60896
+ }
60897
+ if (defaultValue.value === null) return null;
60898
+ if (parameter4.type === 8 /* Enum */) return [defaultValue.value];
60899
+ return defaultValue.value;
60900
+ }
60901
+ function fillCallableCallSiteArguments(args, member, ctx) {
60902
+ if (member === null) return args;
60903
+ if (member.kind !== 13 /* Function */ && member.kind !== 23 /* NSFunction */) {
60904
+ return args;
60905
+ }
60906
+ const signature = resolveCallableSignature(member.id, member.kind, ctx);
60907
+ if (signature === null) return args;
60908
+ if (!hasAnyParameterDefault(signature.argumentTypes)) return args;
60909
+ const subject = member.kind === 13 /* Function */ ? `Function '${member.name}'` : `NSFunction '${member.name}'`;
60910
+ return fillTrailingParameterDefaults(args, signature.argumentTypes, subject);
60911
+ }
59964
60912
  function createChildScope(parent) {
59965
60913
  return new NeoScriptScope(parent);
59966
60914
  }
@@ -61257,8 +62205,11 @@ function evalPointer(pointer, scope, ctx) {
61257
62205
  if (pointer.receiver.kind === "instance" && pointer.optional === true && (innerThis === null || innerThis === void 0)) {
61258
62206
  return null;
61259
62207
  }
61260
- const args = pointer.args.map((arg) => evalPointer(arg, scope, ctx));
62208
+ const suppliedArgs = pointer.args.map(
62209
+ (arg) => evalPointer(arg, scope, ctx)
62210
+ );
61261
62211
  const member = pointer.receiver.kind === "static" ? evalMemberById(ctx.vm, pointer.receiver.memberId) : resolveEffectiveCallableMember(pointer, innerThis, ctx);
62212
+ const args = fillCallableCallSiteArguments(suppliedArgs, member, ctx);
61262
62213
  const interceptedMemberId = member?.id ?? pointer.memberId ?? pointer.memberKey ?? pointer.callSiteId;
61263
62214
  consumeBudget(ctx, "workUnits", 1, "work unit");
61264
62215
  const intercepted = ctx.callInterceptor?.({
@@ -61781,13 +62732,21 @@ function substituteCallableSignatureForReceiver(signature, receiver, ctx) {
61781
62732
  ctx
61782
62733
  ),
61783
62734
  argumentTypes: signature.argumentTypes.map((argument2) => {
62735
+ if (!typeInfoContainsGeneric(argument2)) return argument2;
61784
62736
  const substituted = substituteRuntimeTypeInfo(argument2, env, ctx);
61785
62737
  if (substituted.type === NS_TYPE_VOID) {
61786
62738
  throw new NSGetterRuntimeError(
61787
62739
  `Generic NSFunction argument '${argument2.name}' resolved to Void.`
61788
62740
  );
61789
62741
  }
61790
- return { ...substituted, name: argument2.name };
62742
+ const named = { ...substituted, name: argument2.name };
62743
+ if (argument2.defaultValue === void 0) return named;
62744
+ if (argument2.defaultValue.value !== null) {
62745
+ throw new NSGetterRuntimeError(
62746
+ `Generic NSFunction parameter '${argument2.name}' carries a non-null constant default, which a generic parameter cannot declare.`
62747
+ );
62748
+ }
62749
+ return { ...named, defaultValue: { value: null } };
61791
62750
  })
61792
62751
  };
61793
62752
  } catch (error) {
@@ -64262,15 +65221,21 @@ function resolveDeclaredConstructorRecord(info, schemaClass2, ctx) {
64262
65221
  `Declared constructor call on '${schemaClass2.name}' passes the same argument name twice.`
64263
65222
  );
64264
65223
  }
64265
- if (suppliedNames.length !== record3.argumentTypes.length) {
65224
+ const supplied = new Set(suppliedNames);
65225
+ for (const parameter4 of record3.argumentTypes) {
65226
+ if (supplied.has(parameter4.name)) continue;
65227
+ if (parameterHasDefault(parameter4)) continue;
64266
65228
  throw new NSGetterRuntimeError(
64267
- `Constructor '${record3.id}' on '${schemaClass2.name}' declares ${record3.argumentTypes.length} parameter(s) but the call site passes ${suppliedNames.length}.`
65229
+ `Declared constructor call on '${schemaClass2.name}' has no argument for parameter '${parameter4.name}'.`
64268
65230
  );
64269
65231
  }
64270
- for (const parameter4 of record3.argumentTypes) {
64271
- if (suppliedNames.includes(parameter4.name)) continue;
65232
+ const declaredNames = new Set(
65233
+ record3.argumentTypes.map((parameter4) => parameter4.name)
65234
+ );
65235
+ for (const name of suppliedNames) {
65236
+ if (declaredNames.has(name)) continue;
64272
65237
  throw new NSGetterRuntimeError(
64273
- `Declared constructor call on '${schemaClass2.name}' has no argument for parameter '${parameter4.name}'.`
65238
+ `Declared constructor call on '${schemaClass2.name}' names unknown parameter '${name}'.`
64274
65239
  );
64275
65240
  }
64276
65241
  return record3;
@@ -64281,6 +65246,12 @@ function evaluateDeclaredConstructorArguments(info, record3, scope, ctx) {
64281
65246
  byName.set(argument2.name, evalPointer(argument2.valuePointer, scope, ctx));
64282
65247
  }
64283
65248
  return record3.argumentTypes.map((parameter4) => {
65249
+ if (!byName.has(parameter4.name)) {
65250
+ return parameterDefaultRuntimeValue(
65251
+ parameter4,
65252
+ `Constructor '${record3.id}'`
65253
+ );
65254
+ }
64284
65255
  const value = byName.get(parameter4.name);
64285
65256
  if (parameter4.type !== 20 /* Decimal */) return value;
64286
65257
  if (typeof value !== "number") return value;
@@ -64311,7 +65282,7 @@ function resolveBaseConstructorRecord(record3, ctx) {
64311
65282
  if (baseArguments.length === 0) {
64312
65283
  if (candidates.length === 0) return null;
64313
65284
  const parameterless = candidates.find(
64314
- (candidate) => candidate.argumentTypes.length === 0
65285
+ (candidate) => candidate.argumentTypes.every(parameterHasDefault)
64315
65286
  );
64316
65287
  if (parameterless === void 0) {
64317
65288
  throw new NSGetterRuntimeError(
@@ -64322,17 +65293,32 @@ function resolveBaseConstructorRecord(record3, ctx) {
64322
65293
  }
64323
65294
  const names = new Set(baseArguments.map((argument2) => argument2.name));
64324
65295
  const matches = candidates.filter(
64325
- (candidate) => candidate.argumentTypes.length === names.size && candidate.argumentTypes.every((parameter4) => names.has(parameter4.name))
65296
+ (candidate) => candidate.argumentTypes.every(
65297
+ (parameter4) => names.has(parameter4.name) || parameterHasDefault(parameter4)
65298
+ ) && [...names].every(
65299
+ (name) => candidate.argumentTypes.some((parameter4) => parameter4.name === name)
65300
+ )
64326
65301
  );
64327
- const firstMatch = matches[0];
64328
- if (firstMatch === void 0) {
65302
+ if (matches.length === 0) {
64329
65303
  throw new NSGetterRuntimeError(
64330
65304
  `Constructor '${record3.id}' on '${owningClass.name}' calls ': base(${[...names].join(", ")})', which matches no constructor on its base class.`
64331
65305
  );
64332
65306
  }
64333
- if (matches.length > 1) {
65307
+ const fewestFillIns = Math.min(
65308
+ ...matches.map((candidate) => candidate.argumentTypes.length - names.size)
65309
+ );
65310
+ const best = matches.filter(
65311
+ (candidate) => candidate.argumentTypes.length - names.size === fewestFillIns
65312
+ );
65313
+ const firstMatch = best[0];
65314
+ if (firstMatch === void 0) {
65315
+ throw new NSGetterRuntimeError(
65316
+ `Constructor '${record3.id}' on '${owningClass.name}' resolved ': base(${[...names].join(", ")})' to an empty betterness set.`
65317
+ );
65318
+ }
65319
+ if (best.length > 1) {
64334
65320
  throw new NSGetterRuntimeError(
64335
- `Constructor '${record3.id}' on '${owningClass.name}' calls ': base(${[...names].join(", ")})', which matches ${matches.length} base constructors: ${matches.map((candidate) => candidate.id).join(", ")}.`
65321
+ `Constructor '${record3.id}' on '${owningClass.name}' calls ': base(${[...names].join(", ")})', which matches ${best.length} base constructors: ${best.map((candidate) => candidate.id).join(", ")}.`
64336
65322
  );
64337
65323
  }
64338
65324
  return firstMatch;
@@ -64366,6 +65352,12 @@ function evaluateBaseConstructorArguments(record3, baseRecord, argumentValues, t
64366
65352
  }
64367
65353
  return baseRecord.argumentTypes.map((parameter4) => {
64368
65354
  if (!byName.has(parameter4.name)) {
65355
+ if (parameterHasDefault(parameter4)) {
65356
+ return parameterDefaultRuntimeValue(
65357
+ parameter4,
65358
+ `Constructor '${baseRecord.id}'`
65359
+ );
65360
+ }
64369
65361
  throw new NSGetterRuntimeError(
64370
65362
  `Constructor '${record3.id}' calls ': base(...)' without an argument for base parameter '${parameter4.name}'.`
64371
65363
  );
@@ -66479,12 +67471,15 @@ function isNeoClassConstructorBase(value) {
66479
67471
  if (typeof v.code !== "string" && v.code !== null) return false;
66480
67472
  if (!Array.isArray(v.argumentTypes)) return false;
66481
67473
  const parameterNames = /* @__PURE__ */ new Set();
67474
+ const argumentTypes = [];
66482
67475
  for (const argument2 of v.argumentTypes) {
66483
67476
  if (!isNSFunctionArgumentTypeInfo(argument2)) return false;
66484
67477
  if (!isValidCallableIdentifier(argument2.name)) return false;
66485
67478
  if (parameterNames.has(argument2.name)) return false;
66486
67479
  parameterNames.add(argument2.name);
67480
+ argumentTypes.push(argument2);
66487
67481
  }
67482
+ if (validateParameterDefaults(argumentTypes).length > 0) return false;
66488
67483
  if (v.baseArguments !== void 0 && v.baseArguments !== null) {
66489
67484
  if (!Array.isArray(v.baseArguments)) return false;
66490
67485
  const baseNames = /* @__PURE__ */ new Set();
@@ -76040,7 +77035,7 @@ function stableValue(value) {
76040
77035
  if (Array.isArray(value)) return value.map(stableValue);
76041
77036
  if (!isRecord7(value)) return value;
76042
77037
  const normalized = Object.fromEntries(
76043
- Object.entries(value).filter(([key]) => key !== "name").sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, stableValue(entry)])
77038
+ Object.entries(value).filter(([key]) => key !== "name" && key !== "defaultValue").sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, stableValue(entry)])
76044
77039
  );
76045
77040
  return normalized;
76046
77041
  }
@@ -76142,11 +77137,81 @@ function isOpaqueNSFunctionReturnTypeInfo(value) {
76142
77137
  return isOpaqueNSTypeInfo(value);
76143
77138
  }
76144
77139
  function isOpaqueNSFunctionArgumentTypeInfo(value) {
76145
- return isOpaqueNSTypeInfo(value) && isOpaqueCallableIdentifier(value.name) && !opaqueTypeInfoContainsUnknown(value);
77140
+ return isOpaqueNSTypeInfo(value) && isOpaqueCallableIdentifier(value.name) && !opaqueTypeInfoContainsUnknown(value) && hasValidOpaqueParameterDefault(value);
76146
77141
  }
76147
77142
  function isOpaqueConstructorArgumentTypeInfo(value) {
76148
77143
  if (!isRecord7(value)) return false;
76149
- return isOpaqueNSTypeInfo(value) && (value.name === "value" || isOpaqueCallableIdentifier(value.name)) && !opaqueTypeInfoContainsUnknown(value);
77144
+ return isOpaqueNSTypeInfo(value) && (value.name === "value" || isOpaqueCallableIdentifier(value.name)) && !opaqueTypeInfoContainsUnknown(value) && hasValidOpaqueParameterDefault(value);
77145
+ }
77146
+ function hasValidOpaqueParameterDefault(value) {
77147
+ const wrapper = value.defaultValue;
77148
+ if (wrapper === void 0) return true;
77149
+ if (!isRecord7(wrapper)) return false;
77150
+ const keys = Object.keys(wrapper);
77151
+ if (keys.length !== 1 || keys[0] !== "value") return false;
77152
+ const payload = wrapper.value;
77153
+ if (payload === null) return value.required === false;
77154
+ if (value.type === 1) return typeof payload === "boolean";
77155
+ if (value.type === 2) {
77156
+ return typeof payload === "number" && Number.isInteger(payload);
77157
+ }
77158
+ if (value.type === 4) {
77159
+ return typeof payload === "number" && Number.isFinite(payload);
77160
+ }
77161
+ if (value.type === 3 || value.type === 8 || value.type === 20) {
77162
+ return typeof payload === "string";
77163
+ }
77164
+ return false;
77165
+ }
77166
+ function opaqueParameterDefaultsPlacedLast(argumentTypes) {
77167
+ let seenDefault = false;
77168
+ for (const argument2 of argumentTypes) {
77169
+ if (argument2.defaultValue !== void 0) {
77170
+ seenDefault = true;
77171
+ continue;
77172
+ }
77173
+ if (seenDefault) return false;
77174
+ }
77175
+ return true;
77176
+ }
77177
+ function opaqueArgumentsHaveDefault(argumentTypes) {
77178
+ return argumentTypes.some(
77179
+ (argument2) => isRecord7(argument2) && argument2.defaultValue !== void 0
77180
+ );
77181
+ }
77182
+ function assertOpaqueParameterDefaultsValid(member) {
77183
+ const argumentTypes = member.argumentTypes;
77184
+ if (!Array.isArray(argumentTypes)) return;
77185
+ if (!opaqueArgumentsHaveDefault(argumentTypes)) return;
77186
+ if (member.kind === 25 || member.kind === 26) {
77187
+ throw new Error(
77188
+ `Member "${member.name}" (${member.id}) is a delegate or action, whose parameters are an unnamed positional type list and cannot carry a default value.`
77189
+ );
77190
+ }
77191
+ if (member.kind !== 13 && member.kind !== 23) {
77192
+ throw new Error(
77193
+ `Member "${member.name}" (${member.id}) is not callable and cannot declare parameter default values.`
77194
+ );
77195
+ }
77196
+ if (member.deferred === true) {
77197
+ throw new Error(
77198
+ `Function "${member.name}" (${member.id}) is deferred, and generated C# appends a trailing deferred parameter that a defaulted parameter cannot precede.`
77199
+ );
77200
+ }
77201
+ const parameters = [];
77202
+ for (const argument2 of argumentTypes) {
77203
+ if (!isRecord7(argument2) || !hasValidOpaqueParameterDefault(argument2)) {
77204
+ throw new Error(
77205
+ `Function "${member.name}" (${member.id}) declares a parameter default value that does not match the parameter's type.`
77206
+ );
77207
+ }
77208
+ parameters.push(argument2);
77209
+ }
77210
+ if (!opaqueParameterDefaultsPlacedLast(parameters)) {
77211
+ throw new Error(
77212
+ `Function "${member.name}" (${member.id}) declares a defaulted parameter before a non-defaulted one; defaulted parameters must come last.`
77213
+ );
77214
+ }
76150
77215
  }
76151
77216
  function memberSignature(member) {
76152
77217
  if (member.kind === "property") {
@@ -76180,6 +77245,7 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
76180
77245
  }
76181
77246
  for (const member of members) {
76182
77247
  assertOpaqueMemberDefaultValueValid(member);
77248
+ assertOpaqueParameterDefaultsValid(member);
76183
77249
  assertOpaqueCallableOverrideValid(member, membersById);
76184
77250
  assertOpaqueNSFunctionValid(member, membersById);
76185
77251
  if (member.isAbstract === true && member.defaultValue != null) {
@@ -77556,11 +78622,11 @@ function assertOpaqueConstructorValid(declaredConstructor) {
77556
78622
  );
77557
78623
  }
77558
78624
  names.add(name);
77559
- if (argument2.defaultValue !== void 0) {
77560
- throw new Error(
77561
- `Constructor "${declaredConstructor.id}" parameter "${name}" declares a default value, which constructors do not support; add an overload instead.`
77562
- );
77563
- }
78625
+ }
78626
+ if (!opaqueParameterDefaultsPlacedLast(argumentTypes)) {
78627
+ throw new Error(
78628
+ `Constructor "${declaredConstructor.id}" declares a defaulted parameter before a non-defaulted one; defaulted parameters must come last.`
78629
+ );
77564
78630
  }
77565
78631
  assertOpaqueCompiledConstructorAction(declaredConstructor, argumentTypes);
77566
78632
  assertOpaqueConstructorBaseClauseValid(declaredConstructor);
@@ -103403,8 +104469,8 @@ var init_registry2 = __esm({
103403
104469
  "use strict";
103404
104470
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
103405
104471
  formatVersion: 3,
103406
- contractVersion: "3.9",
103407
- cliVersion: "0.27.1",
104472
+ contractVersion: "3.10",
104473
+ cliVersion: "0.28.0",
103408
104474
  projectFileUploadBatchSize: 32,
103409
104475
  documentRecords: {
103410
104476
  member: {
@@ -109970,7 +111036,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
109970
111036
  async function main() {
109971
111037
  const args = parseArgs(process.argv.slice(2));
109972
111038
  if (args.command === "--version") {
109973
- console.log("0.27.1");
111039
+ console.log("0.28.0");
109974
111040
  return;
109975
111041
  }
109976
111042
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {