@neocompose/cli 0.32.3 → 0.33.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
@@ -2833,12 +2833,6 @@ function referenceAtPosition(snapshot, position) {
2833
2833
  snapshot.source.offsetAt(position)
2834
2834
  );
2835
2835
  }
2836
- function isValidNeoIdentifier(name) {
2837
- return IDENTIFIER_PATTERN.test(name) && !RESERVED_NAMES.has(name);
2838
- }
2839
- function isValidRenameIdentifier(name) {
2840
- return isValidNeoIdentifier(name);
2841
- }
2842
2836
  function contextualCompletionItems(snapshot, offset, word) {
2843
2837
  const items = [];
2844
2838
  const expectedType = expectedTypeAt(snapshot, word.start);
@@ -4609,20 +4603,11 @@ function isConstructorTypeReference(snapshot, reference2) {
4609
4603
  (call) => call.kind === "constructor" && call.nameRange.start.line === reference2.range.start.line && call.nameRange.start.character === reference2.range.start.character
4610
4604
  );
4611
4605
  }
4612
- var IDENTIFIER_PATTERN, RESERVED_NAMES;
4613
4606
  var init_analyzer = __esm({
4614
4607
  "../packages/neoscript-language/src/analyzer.ts"() {
4615
4608
  "use strict";
4616
4609
  init_language_spec();
4617
4610
  init_project();
4618
- IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
4619
- RESERVED_NAMES = /* @__PURE__ */ new Set([
4620
- ...NEOSCRIPT_KEYWORDS,
4621
- ...NEOSCRIPT_PRIMITIVE_TYPES,
4622
- ...NEOSCRIPT_BUILTIN_NAMESPACES,
4623
- "Dictionary",
4624
- "Set"
4625
- ]);
4626
4611
  }
4627
4612
  });
4628
4613
 
@@ -5923,10 +5908,22 @@ var init_strict_compile_error = __esm({
5923
5908
  function isValidNeoProjectIdentifier(name) {
5924
5909
  return PROJECT_IDENTIFIER_PATTERN.test(name) && !PROJECT_RESERVED_NAMES.has(name);
5925
5910
  }
5911
+ function isValidNeoProjectMemberIdentifier(name) {
5912
+ return PROJECT_IDENTIFIER_PATTERN.test(name) && !PROJECT_MEMBER_RESERVED_NAMES.has(name);
5913
+ }
5914
+ function isValidNeoProjectBindingIdentifier(name) {
5915
+ return PROJECT_IDENTIFIER_PATTERN.test(name) && !PROJECT_BINDING_RESERVED_NAMES.has(name);
5916
+ }
5917
+ function isValidNeoScriptBindingIdentifier(name) {
5918
+ return PROJECT_IDENTIFIER_PATTERN.test(name) && !INLINE_BINDING_RESERVED_NAMES.has(name);
5919
+ }
5926
5920
  function isNeoProjectReservedName(name) {
5927
5921
  return PROJECT_RESERVED_NAMES.has(name);
5928
5922
  }
5929
- var PROJECT_IDENTIFIER_PATTERN, PROJECT_RESERVED_NAMES;
5923
+ function isNeoProjectMemberReservedName(name) {
5924
+ return PROJECT_MEMBER_RESERVED_NAMES.has(name);
5925
+ }
5926
+ var PROJECT_IDENTIFIER_PATTERN, PROJECT_RESERVED_NAMES, PROJECT_MEMBER_RESERVED_NAMES, PROJECT_BINDING_RESERVED_NAMES, INLINE_BINDING_RESERVED_NAMES;
5930
5927
  var init_project_source_identifiers = __esm({
5931
5928
  "../packages/neoscript-language/src/project-source-identifiers.ts"() {
5932
5929
  "use strict";
@@ -5936,6 +5933,20 @@ var init_project_source_identifiers = __esm({
5936
5933
  ...NEOSCRIPT_KEYWORDS,
5937
5934
  ...NEOSCRIPT_BUILTIN_NAMESPACES
5938
5935
  ]);
5936
+ PROJECT_MEMBER_RESERVED_NAMES = new Set(NEOSCRIPT_KEYWORDS);
5937
+ PROJECT_BINDING_RESERVED_NAMES = /* @__PURE__ */ new Set([
5938
+ ...PROJECT_RESERVED_NAMES,
5939
+ "this",
5940
+ "root",
5941
+ "context"
5942
+ ]);
5943
+ INLINE_BINDING_RESERVED_NAMES = /* @__PURE__ */ new Set([
5944
+ ...PROJECT_BINDING_RESERVED_NAMES,
5945
+ ...NEOSCRIPT_PRIMITIVE_TYPES,
5946
+ "Dictionary",
5947
+ "List",
5948
+ "Set"
5949
+ ]);
5939
5950
  }
5940
5951
  });
5941
5952
 
@@ -6456,12 +6467,26 @@ function makeBinary(op, left, right, pos) {
6456
6467
  return { kind: "binary", op, left, right, pos };
6457
6468
  }
6458
6469
  function asASTBinaryOp(text) {
6459
- if (!AST_BINARY_OPS.has(text)) {
6460
- throw new Error(
6461
- `Internal compiler error: '${text}' is not a valid ASTBinaryOp`
6462
- );
6470
+ switch (text) {
6471
+ case "+":
6472
+ case "-":
6473
+ case "*":
6474
+ case "/":
6475
+ case "%":
6476
+ case "==":
6477
+ case "!=":
6478
+ case "<":
6479
+ case ">":
6480
+ case "<=":
6481
+ case ">=":
6482
+ case "&&":
6483
+ case "||":
6484
+ return text;
6485
+ default:
6486
+ throw new Error(
6487
+ `Internal compiler error: '${text}' is not a valid ASTBinaryOp`
6488
+ );
6463
6489
  }
6464
- return text;
6465
6490
  }
6466
6491
  function isAssignmentOp(token) {
6467
6492
  return token.kind === "op" && (token.text === "=" || token.text === "+=" || token.text === "-=" || token.text === "*=" || token.text === "/=" || token.text === "%=");
@@ -6477,7 +6502,7 @@ function describeToken(t) {
6477
6502
  if (t.kind === "eof") return "end of input";
6478
6503
  return `'${t.text}'`;
6479
6504
  }
6480
- var Parser, AST_BINARY_OPS;
6505
+ var Parser;
6481
6506
  var init_strict_parser = __esm({
6482
6507
  "../packages/neoscript-language/src/strict-parser.ts"() {
6483
6508
  "use strict";
@@ -6522,7 +6547,7 @@ var init_strict_parser = __esm({
6522
6547
  }
6523
6548
  expectMemberName() {
6524
6549
  const token = this.peek();
6525
- if (token.kind === "ident" || token.kind === "keyword" && (token.text === "native" || isValidNeoProjectIdentifier(token.text))) {
6550
+ if (token.kind === "ident" || token.kind === "keyword" && (token.text === "native" || isValidNeoProjectMemberIdentifier(token.text))) {
6526
6551
  return this.next();
6527
6552
  }
6528
6553
  throw new CompileError(
@@ -6968,7 +6993,7 @@ var init_strict_parser = __esm({
6968
6993
  // Types
6969
6994
  // ------------------------------------------------------------------
6970
6995
  /** Parses a type annotation (used in varDecls and Dictionary generics). */
6971
- parseType() {
6996
+ parseType(options = {}) {
6972
6997
  const startPos = this.peek().pos;
6973
6998
  let inner;
6974
6999
  const t = this.peek();
@@ -7034,17 +7059,73 @@ var init_strict_parser = __esm({
7034
7059
  pos: arrPos
7035
7060
  };
7036
7061
  }
7037
- if (this.peek().kind === "op" && this.peek().text === "?") {
7062
+ if (this.peek().kind === "op" && this.peek().text === "?" && !(options.conditionalQuestion === true && this.hasMatchingConditionalColon(this.i))) {
7038
7063
  this.next();
7039
7064
  inner = { ...inner, required: false };
7040
7065
  }
7041
7066
  return inner;
7042
7067
  }
7068
+ /**
7069
+ * `is T ? a : b` is ambiguous at the token level because `?` is also the
7070
+ * nullable type suffix. A colon at the same delimiter depth makes it the
7071
+ * conditional operator; nested ternaries are paired before the outer colon.
7072
+ */
7073
+ hasMatchingConditionalColon(questionIndex) {
7074
+ let delimiterDepth2 = 0;
7075
+ let nestedQuestions = 0;
7076
+ for (let index = questionIndex + 1; index < this.tokens.length; index += 1) {
7077
+ const token = this.tokens[index];
7078
+ if (token === void 0) return false;
7079
+ if (token.kind === "punct") {
7080
+ if (token.text === "(" || token.text === "[" || token.text === "{") {
7081
+ delimiterDepth2 += 1;
7082
+ continue;
7083
+ }
7084
+ if (token.text === ")" || token.text === "]" || token.text === "}") {
7085
+ if (delimiterDepth2 === 0) return false;
7086
+ delimiterDepth2 -= 1;
7087
+ continue;
7088
+ }
7089
+ if (delimiterDepth2 !== 0) continue;
7090
+ if (token.text === ";" || token.text === ",") return false;
7091
+ if (token.text !== ":") continue;
7092
+ if (nestedQuestions === 0) return true;
7093
+ nestedQuestions -= 1;
7094
+ continue;
7095
+ }
7096
+ if (delimiterDepth2 === 0 && token.kind === "op" && token.text === "?") {
7097
+ nestedQuestions += 1;
7098
+ }
7099
+ }
7100
+ return false;
7101
+ }
7043
7102
  // ------------------------------------------------------------------
7044
7103
  // Expressions — climbing precedence (lowest first)
7045
7104
  // ------------------------------------------------------------------
7046
7105
  parseExpr() {
7047
- return this.parseCoalesce();
7106
+ return this.parseConditional();
7107
+ }
7108
+ /**
7109
+ * Conditional `condition ? whenTrue : whenFalse`. This is the lowest
7110
+ * precedence expression operator and is right-associative, matching the
7111
+ * familiar C#/TypeScript reading of nested ternaries.
7112
+ */
7113
+ parseConditional() {
7114
+ const condition = this.parseCoalesce();
7115
+ if (!(this.peek().kind === "op" && this.peek().text === "?")) {
7116
+ return condition;
7117
+ }
7118
+ const question = this.next();
7119
+ const whenTrue = this.parseExpr();
7120
+ this.expect("punct", ":");
7121
+ const whenFalse = this.parseConditional();
7122
+ return {
7123
+ kind: "conditional",
7124
+ condition,
7125
+ whenTrue,
7126
+ whenFalse,
7127
+ pos: question.pos
7128
+ };
7048
7129
  }
7049
7130
  /**
7050
7131
  * Null-coalesce `lhs ?? rhs`. Lower precedence than `||` / `&&` so
@@ -7092,7 +7173,7 @@ var init_strict_parser = __esm({
7092
7173
  }
7093
7174
  if (t.kind === "keyword" && t.text === "is") {
7094
7175
  this.next();
7095
- const type = this.parseType();
7176
+ const type = this.parseType({ conditionalQuestion: true });
7096
7177
  const bindingName = this.peek().kind === "ident" ? this.next().text : null;
7097
7178
  left = { kind: "is", operand: left, type, bindingName, pos: t.pos };
7098
7179
  continue;
@@ -7527,13 +7608,8 @@ var init_strict_parser = __esm({
7527
7608
  */
7528
7609
  parseLambdaParam() {
7529
7610
  const startPos = this.peek().pos;
7530
- const t = this.peek();
7531
- if (t.kind === "keyword" && (t.text === "int" || t.text === "float" || t.text === "bool" || t.text === "string" || t.text === "Dictionary")) {
7532
- const type = this.parseType();
7533
- const name2 = this.expect("ident");
7534
- return { type, name: name2.text, pos: startPos };
7535
- }
7536
- if (t.kind === "ident" && this.tokens[this.i + 1]?.kind === "ident") {
7611
+ const afterType = this.scanType(this.i);
7612
+ if (afterType !== null && this.tokens[afterType]?.kind === "ident") {
7537
7613
  const type = this.parseType();
7538
7614
  const name2 = this.expect("ident");
7539
7615
  return { type, name: name2.text, pos: startPos };
@@ -7596,21 +7672,6 @@ var init_strict_parser = __esm({
7596
7672
  return { kind: "litInterp", parts, pos };
7597
7673
  }
7598
7674
  };
7599
- AST_BINARY_OPS = /* @__PURE__ */ new Set([
7600
- "+",
7601
- "-",
7602
- "*",
7603
- "/",
7604
- "%",
7605
- "==",
7606
- "!=",
7607
- "<",
7608
- ">",
7609
- "<=",
7610
- ">=",
7611
- "&&",
7612
- "||"
7613
- ]);
7614
7675
  }
7615
7676
  });
7616
7677
 
@@ -8214,7 +8275,7 @@ var NEOSCRIPT_COMPILER_REVISION;
8214
8275
  var init_strict_ir = __esm({
8215
8276
  "../packages/neoscript-language/src/strict-ir.ts"() {
8216
8277
  "use strict";
8217
- NEOSCRIPT_COMPILER_REVISION = 11;
8278
+ NEOSCRIPT_COMPILER_REVISION = 12;
8218
8279
  }
8219
8280
  });
8220
8281
 
@@ -8617,6 +8678,11 @@ function collectAssignedPathRootsInExpression(expression, roots) {
8617
8678
  collectAssignedPathRootsInExpression(expression.left, roots);
8618
8679
  collectAssignedPathRootsInExpression(expression.right, roots);
8619
8680
  return;
8681
+ case "conditional":
8682
+ collectAssignedPathRootsInExpression(expression.condition, roots);
8683
+ collectAssignedPathRootsInExpression(expression.whenTrue, roots);
8684
+ collectAssignedPathRootsInExpression(expression.whenFalse, roots);
8685
+ return;
8620
8686
  case "unary":
8621
8687
  case "force":
8622
8688
  collectAssignedPathRootsInExpression(expression.operand, roots);
@@ -9504,6 +9570,7 @@ var init_strict_resolver = __esm({
9504
9570
  this.context = context;
9505
9571
  this.source = source;
9506
9572
  this.project = projectIndex ?? createProjectIndex(context.project);
9573
+ this.sourceTokens = source === void 0 ? void 0 : lex2(source);
9507
9574
  const unknown = { kind: "primitive", name: "unknown" };
9508
9575
  this.thisVariable = variable(
9509
9576
  "__this__",
@@ -9549,6 +9616,9 @@ var init_strict_resolver = __esm({
9549
9616
  argumentVariables;
9550
9617
  callSiteCounter = 0;
9551
9618
  lambdaDepth = 0;
9619
+ delegateClosureCounter = 0;
9620
+ delegateCaptureContexts = [];
9621
+ sourceTokens;
9552
9622
  unreachableControlEffectDepth = 0;
9553
9623
  catchBindingCounter = 0;
9554
9624
  catchContexts = [];
@@ -10265,6 +10335,12 @@ var init_strict_resolver = __esm({
10265
10335
  case "assign":
10266
10336
  return this.resolveAssignment(statement, scope);
10267
10337
  case "exprStmt": {
10338
+ const actionClear = this.resolveActionClear(
10339
+ statement.expr,
10340
+ scope,
10341
+ statement.pos
10342
+ );
10343
+ if (actionClear) return actionClear;
10268
10344
  const collectionCall = this.resolveCollectionMutation(
10269
10345
  statement.expr,
10270
10346
  scope,
@@ -10409,7 +10485,10 @@ var init_strict_resolver = __esm({
10409
10485
  pos
10410
10486
  );
10411
10487
  }
10412
- if (!scope.lookup(name)) return;
10488
+ const usedInLexicalOuter = this.delegateCaptureContexts.some(
10489
+ (context) => context.outerScope.lookup(name) !== null
10490
+ );
10491
+ if (!scope.lookup(name) && !usedInLexicalOuter) return;
10413
10492
  throw new CompileError(
10414
10493
  `Cannot declare local '${name}' because that name is already used in an enclosing or current scope.`,
10415
10494
  pos
@@ -10568,7 +10647,9 @@ var init_strict_resolver = __esm({
10568
10647
  }
10569
10648
  const local = statement.target.kind === "ident" ? scope.lookup(statement.target.name) : null;
10570
10649
  if (local?.readonlyBinding) {
10571
- const label = local.readonlyBinding === "catch" ? "catch parameter" : "foreach iterator";
10650
+ let label = "foreach iterator";
10651
+ if (local.readonlyBinding === "catch") label = "catch parameter";
10652
+ if (local.readonlyBinding === "capture") label = "captured value";
10572
10653
  throw new CompileError(
10573
10654
  `Cannot assign to ${label} '${local.name}' because it is read-only.`,
10574
10655
  statement.pos
@@ -11168,6 +11249,8 @@ var init_strict_resolver = __esm({
11168
11249
  type: resultType
11169
11250
  };
11170
11251
  }
11252
+ case "conditional":
11253
+ return this.resolveConditionalExpression(expression, scope, expected);
11171
11254
  case "is": {
11172
11255
  const operand = this.resolveExpression(expression.operand, scope);
11173
11256
  const check = this.resolveType(expression.type);
@@ -11212,19 +11295,40 @@ var init_strict_resolver = __esm({
11212
11295
  ast.pos
11213
11296
  );
11214
11297
  }
11215
- const scope = new Scope(outerScope);
11298
+ const serial = this.delegateClosureCounter++;
11299
+ const scope = new Scope(null);
11300
+ scope.define(
11301
+ scopeVariable(
11302
+ "this",
11303
+ this.thisVariable,
11304
+ this.context.thisClass,
11305
+ void 0,
11306
+ "runtime" /* Runtime */
11307
+ )
11308
+ );
11309
+ const rootSymbol = this.context.project.roots.find(
11310
+ (candidate) => candidate.name === "root"
11311
+ );
11312
+ scope.define(scopeVariable("root", this.rootVariable, rootSymbol?.type));
11216
11313
  const parameters = ast.params.map((parameter4, index) => {
11314
+ this.assertLocalNameAvailable(parameter4.name, outerScope, parameter4.pos);
11217
11315
  this.assertLocalNameAvailable(parameter4.name, scope, parameter4.pos);
11218
11316
  const expectedType = requiredAt(expected.parameterTypes, index);
11219
11317
  const declared = parameter4.type ? this.resolveType(parameter4.type) : expectedType;
11220
- if (!isNeoScriptTypeAssignable(declared, expectedType, this.project) || !isNeoScriptTypeAssignable(expectedType, declared, this.project)) {
11318
+ if (!isNeoScriptTypeAssignable(declared, expectedType, this.project)) {
11221
11319
  throw new CompileError(
11222
- `Delegate lambda parameter ${index + 1} must be ${this.describe(expectedType)}, got ${this.describe(declared)}.`,
11320
+ `Delegate lambda parameter ${index + 1} type ${this.describe(declared)} is not assignable to ${this.describe(expectedType)}.`,
11321
+ parameter4.pos
11322
+ );
11323
+ }
11324
+ if (!isNeoScriptTypeAssignable(expectedType, declared, this.project)) {
11325
+ throw new CompileError(
11326
+ `Delegate lambda parameter ${index + 1} type ${this.describe(declared)} is broader than the declared delegate parameter ${this.describe(expectedType)}.`,
11223
11327
  parameter4.pos
11224
11328
  );
11225
11329
  }
11226
11330
  const item = variable(
11227
- `__arg_${index}__`,
11331
+ `__lambda_${serial}_arg_${index}__`,
11228
11332
  declared,
11229
11333
  void 0,
11230
11334
  this.project
@@ -11240,6 +11344,14 @@ var init_strict_resolver = __esm({
11240
11344
  );
11241
11345
  return item;
11242
11346
  });
11347
+ const captureContext = {
11348
+ outerScope,
11349
+ closureScope: scope,
11350
+ serial,
11351
+ captures: [],
11352
+ byOuterEntry: /* @__PURE__ */ new Map()
11353
+ };
11354
+ this.delegateCaptureContexts.push(captureContext);
11243
11355
  this.functionControlBoundaries.push({
11244
11356
  controlDepth: this.controlContexts.length,
11245
11357
  loopFlowDepth: this.loopFlowContexts.length,
@@ -11258,11 +11370,34 @@ var init_strict_resolver = __esm({
11258
11370
  }
11259
11371
  const action = {
11260
11372
  compilerRevision: NEOSCRIPT_COMPILER_REVISION,
11261
- parameters: [this.thisVariable, this.rootVariable, ...parameters],
11373
+ parameters: [
11374
+ this.thisVariable,
11375
+ this.rootVariable,
11376
+ ...parameters,
11377
+ ...captureContext.captures.map((capture) => capture.parameter)
11378
+ ],
11262
11379
  instructions,
11263
11380
  typeInfo: returnsVoid ? toWireType({ kind: "primitive", name: "null" }, this.project) : toWireType(expected.returnType, this.project)
11264
11381
  };
11265
11382
  const code = this.delegateLambdaSource(ast);
11383
+ if (captureContext.captures.length > 0) {
11384
+ const typeInfo = toWireType(expected, this.project);
11385
+ if (typeInfo.type !== 25 /* Delegate */) {
11386
+ throw new Error(
11387
+ "NeoScript delegate closure lowered with non-delegate type info."
11388
+ );
11389
+ }
11390
+ return {
11391
+ pointer: {
11392
+ type: "delegateClosure" /* DelegateClosure */,
11393
+ typeInfo,
11394
+ action,
11395
+ captures: captureContext.captures.map((capture) => capture.source),
11396
+ ...code === void 0 ? {} : { code }
11397
+ },
11398
+ type: expected
11399
+ };
11400
+ }
11266
11401
  return literal(
11267
11402
  expected,
11268
11403
  code === void 0 ? { action } : { code, action },
@@ -11272,11 +11407,14 @@ var init_strict_resolver = __esm({
11272
11407
  this.expectedReturnStack.pop();
11273
11408
  this.lambdaDepth--;
11274
11409
  this.functionControlBoundaries.pop();
11410
+ this.delegateCaptureContexts.pop();
11275
11411
  }
11276
11412
  }
11277
11413
  delegateLambdaSource(ast) {
11278
- if (this.source === void 0) return void 0;
11279
- const tokens = lex2(this.source);
11414
+ if (this.source === void 0 || this.sourceTokens === void 0) {
11415
+ return void 0;
11416
+ }
11417
+ const tokens = this.sourceTokens;
11280
11418
  const startIndex = tokens.findIndex(
11281
11419
  (token) => token.pos.line === ast.pos.line && token.pos.column === ast.pos.column
11282
11420
  );
@@ -11595,7 +11733,7 @@ var init_strict_resolver = __esm({
11595
11733
  };
11596
11734
  }
11597
11735
  resolveIdentifier(name, scope, pos) {
11598
- const entry = scope.lookup(name);
11736
+ const entry = scope.lookup(name) ?? this.captureDelegateOuterBinding(name);
11599
11737
  if (entry) {
11600
11738
  const ownership = scope.ownership(entry) ?? entry.writability;
11601
11739
  return {
@@ -11648,6 +11786,52 @@ var init_strict_resolver = __esm({
11648
11786
  }
11649
11787
  throw new CompileError(`Unknown identifier '${name}'`, pos);
11650
11788
  }
11789
+ /**
11790
+ * Materializes one free delegate-lambda binding as an explicit trailing
11791
+ * action parameter. The pointer stored beside it is evaluated once at the
11792
+ * lambda expression site, giving NeoScript deterministic by-value capture
11793
+ * semantics that survive return, assignment, and persistence.
11794
+ */
11795
+ captureDelegateOuterBinding(name) {
11796
+ const context = this.delegateCaptureContexts.at(-1);
11797
+ if (context === void 0) return null;
11798
+ let outerEntry = context.outerScope.lookup(name);
11799
+ if (outerEntry === null && this.delegateCaptureContexts.length > 1) {
11800
+ const current = this.delegateCaptureContexts.pop();
11801
+ try {
11802
+ this.captureDelegateOuterBinding(name);
11803
+ } finally {
11804
+ if (current !== void 0) this.delegateCaptureContexts.push(current);
11805
+ }
11806
+ outerEntry = context.outerScope.lookup(name);
11807
+ }
11808
+ if (outerEntry === null) return null;
11809
+ const existing = context.byOuterEntry.get(outerEntry);
11810
+ if (existing !== void 0) return existing;
11811
+ const parameter4 = variable(
11812
+ `__capture_${context.serial}_${context.captures.length}__`,
11813
+ outerEntry.type,
11814
+ void 0,
11815
+ this.project
11816
+ );
11817
+ const entry = scopeVariable(
11818
+ name,
11819
+ parameter4,
11820
+ outerEntry.type,
11821
+ "local" /* Local */,
11822
+ "local" /* Local */,
11823
+ outerEntry.writeRoot,
11824
+ "capture"
11825
+ );
11826
+ const source = outerEntry.pointer ?? {
11827
+ type: "variable" /* Variable */,
11828
+ variableId: outerEntry.variableId
11829
+ };
11830
+ context.byOuterEntry.set(outerEntry, entry);
11831
+ context.captures.push({ outerEntry, source, parameter: parameter4, entry });
11832
+ context.closureScope.define(entry);
11833
+ return entry;
11834
+ }
11651
11835
  resolveContextualEnum(optionName, expected, pos) {
11652
11836
  if (!expected || expected.kind !== "named") {
11653
11837
  throw new CompileError(
@@ -12827,6 +13011,37 @@ var init_strict_resolver = __esm({
12827
13011
  );
12828
13012
  }
12829
13013
  const memberReceiverType = neoScriptMemberLookupType(receiver.type);
13014
+ if (callee.name === "Equals" && memberReceiverType.kind === "typeParameter") {
13015
+ if (optional) {
13016
+ throw new CompileError(
13017
+ "Equals cannot be optional-chained on a generic receiver; narrow it with a null check first.",
13018
+ pos
13019
+ );
13020
+ }
13021
+ if (isNullable(receiver.type)) {
13022
+ throw new CompileError(
13023
+ "Equals cannot be called on an optional generic receiver; narrow it with a null check first.",
13024
+ pos
13025
+ );
13026
+ }
13027
+ requireArgCount("Equals", argumentsList2, 1, pos);
13028
+ const other = this.resolveExpression(
13029
+ requiredAt(argumentsList2, 0),
13030
+ scope,
13031
+ { ...memberReceiverType, nullable: true }
13032
+ );
13033
+ return {
13034
+ pointer: {
13035
+ type: "callFunction" /* CallFunction */,
13036
+ memberKey: "Equals",
13037
+ receiver: { kind: "instance", pointer: receiver.pointer },
13038
+ args: [other.pointer],
13039
+ missingMemberFallback: "valueEquality",
13040
+ callSiteId: this.nextCallSite(pos)
13041
+ },
13042
+ type: { kind: "primitive", name: "bool" }
13043
+ };
13044
+ }
12830
13045
  if (memberReceiverType.kind === "named") {
12831
13046
  const type = this.project.typeById.get(memberReceiverType.typeId);
12832
13047
  const member = type?.members.find(
@@ -14423,6 +14638,159 @@ var init_strict_resolver = __esm({
14423
14638
  args
14424
14639
  };
14425
14640
  }
14641
+ /**
14642
+ * `NeoAction.Clear()` resets the stored listener set. It lowers to an
14643
+ * ordinary whole-member assignment so every existing write host observes
14644
+ * the same overlay and write-intent contract as `+=` / `-=`.
14645
+ */
14646
+ resolveActionClear(expression, scope, pos) {
14647
+ if (expression.kind !== "call" || expression.callee.kind !== "member" || expression.callee.name !== "Clear") {
14648
+ return null;
14649
+ }
14650
+ const receiver = this.resolveExpression(expression.callee.receiver, scope);
14651
+ if (receiver.type.kind !== "action") return null;
14652
+ if (expression.callee.optional) {
14653
+ throw new CompileError(
14654
+ `${this.describe(receiver.type)} is never null, so optional-chained Clear is not supported.`,
14655
+ pos
14656
+ );
14657
+ }
14658
+ requireArgCount("Clear", expression.args, 0, pos);
14659
+ if (!isActionMemberPointer(receiver.pointer)) {
14660
+ throw new CompileError(
14661
+ `Cannot clear ${this.describe(receiver.type)} that is not a member reference; an action is not a value. Clear it through the member reference directly.`,
14662
+ pos
14663
+ );
14664
+ }
14665
+ if (receiver.symbol?.computed === true) {
14666
+ throw new CompileError(
14667
+ `Cannot clear NeoScript property '${receiver.symbol.name}'; an action listener set must be stored data.`,
14668
+ pos
14669
+ );
14670
+ }
14671
+ const writability = receiver.writability;
14672
+ if (writability === "immutable" /* Immutable */) {
14673
+ throw new CompileError(
14674
+ "Cannot clear an action whose effective storage is immutable.",
14675
+ pos
14676
+ );
14677
+ }
14678
+ if (!writability) {
14679
+ throw new CompileError(
14680
+ "Cannot clear an action whose member writability could not be resolved.",
14681
+ pos
14682
+ );
14683
+ }
14684
+ if (writability === "readOnly" /* ReadOnly */) {
14685
+ throw new CompileError("Cannot clear a read-only action.", pos);
14686
+ }
14687
+ this.validateConstructorWriteTarget(
14688
+ receiver.pointer,
14689
+ "mutate",
14690
+ pos,
14691
+ scope,
14692
+ true
14693
+ );
14694
+ const path = canonicalPath(expression.callee.receiver);
14695
+ if (path) {
14696
+ const rootEntry = scope.lookup(pathRoot(path));
14697
+ if (rootEntry) scope.invalidate(rootEntry);
14698
+ }
14699
+ const actionTypeInfo = receiver.wireType ?? toWireType(receiver.type, this.project);
14700
+ return {
14701
+ type: "assign" /* Assign */,
14702
+ target: {
14703
+ pointer: receiver.pointer,
14704
+ typeInfo: actionTypeInfo,
14705
+ writability
14706
+ },
14707
+ operator: "=" /* Assign */,
14708
+ pointer: {
14709
+ type: "value" /* Value */,
14710
+ value: { typeInfo: actionTypeInfo, value: { listeners: [] } }
14711
+ }
14712
+ };
14713
+ }
14714
+ resolveConditionalExpression(expression, scope, expected) {
14715
+ const condition = this.toBool(
14716
+ this.resolveExpression(expression.condition, scope),
14717
+ expression.condition.pos
14718
+ );
14719
+ const trueScope = new Scope(scope);
14720
+ this.applyFactsToScope(
14721
+ scope,
14722
+ trueScope,
14723
+ factsWhenTrue(expression.condition)
14724
+ );
14725
+ const falseScope = new Scope(scope);
14726
+ this.applyFactsToScope(
14727
+ scope,
14728
+ falseScope,
14729
+ factsWhenFalse(expression.condition)
14730
+ );
14731
+ let whenTrue;
14732
+ let whenFalse;
14733
+ if (expected) {
14734
+ whenTrue = this.resolveExpression(
14735
+ expression.whenTrue,
14736
+ trueScope,
14737
+ expected
14738
+ );
14739
+ whenFalse = this.resolveExpression(
14740
+ expression.whenFalse,
14741
+ falseScope,
14742
+ expected
14743
+ );
14744
+ } else if (expression.whenTrue.kind === "litNull" || expression.whenTrue.kind === "contextualEnum") {
14745
+ whenFalse = this.resolveExpression(expression.whenFalse, falseScope);
14746
+ whenTrue = this.resolveExpression(expression.whenTrue, trueScope, {
14747
+ ...whenFalse.type,
14748
+ nullable: true
14749
+ });
14750
+ } else {
14751
+ whenTrue = this.resolveExpression(expression.whenTrue, trueScope);
14752
+ whenFalse = this.resolveExpression(
14753
+ expression.whenFalse,
14754
+ falseScope,
14755
+ expression.whenFalse.kind === "litNull" ? { ...whenTrue.type, nullable: true } : whenTrue.type
14756
+ );
14757
+ }
14758
+ const common = commonNeoScriptAssignableType(
14759
+ whenTrue.type,
14760
+ whenFalse.type,
14761
+ this.project
14762
+ );
14763
+ const resultType = common ?? (expected && isNeoScriptTypeAssignable(whenTrue.type, expected, this.project) && isNeoScriptTypeAssignable(whenFalse.type, expected, this.project) ? expected : null);
14764
+ if (!resultType) {
14765
+ throw new CompileError(
14766
+ `Conditional branches ${this.describe(whenTrue.type)} and ${this.describe(whenFalse.type)} do not have a common assignable type.`,
14767
+ expression.pos
14768
+ );
14769
+ }
14770
+ if (expected) {
14771
+ this.requireAssignable(
14772
+ whenTrue.type,
14773
+ expected,
14774
+ expression.whenTrue.pos,
14775
+ "conditional true branch"
14776
+ );
14777
+ this.requireAssignable(
14778
+ whenFalse.type,
14779
+ expected,
14780
+ expression.whenFalse.pos,
14781
+ "conditional false branch"
14782
+ );
14783
+ }
14784
+ return {
14785
+ pointer: {
14786
+ type: "conditional" /* Conditional */,
14787
+ condition: condition.pointer,
14788
+ whenTrue: whenTrue.pointer,
14789
+ whenFalse: whenFalse.pointer
14790
+ },
14791
+ type: resultType
14792
+ };
14793
+ }
14426
14794
  resolveBinary(expression, scope) {
14427
14795
  let left;
14428
14796
  let preResolvedRight;
@@ -14635,6 +15003,15 @@ var init_strict_resolver = __esm({
14635
15003
  type.pos
14636
15004
  );
14637
15005
  }
15006
+ const declaringTypeRef = this.context.declaringType ?? this.context.thisClass;
15007
+ const declaringType = declaringTypeRef?.kind === "named" ? this.project.typeById.get(declaringTypeRef.typeId) : void 0;
15008
+ const typeParameter2 = declaringType?.typeParameters?.find(
15009
+ (candidate) => candidate.name === type.name
15010
+ );
15011
+ if (typeParameter2?.type.kind === "typeParameter") {
15012
+ resolved = typeParameter2.type;
15013
+ break;
15014
+ }
14638
15015
  const builtin = namedPrimitive(type.name);
14639
15016
  if (builtin) {
14640
15017
  resolved = { kind: "primitive", name: builtin };
@@ -17961,12 +18338,15 @@ function projectTokenAt(document, position) {
17961
18338
  const containing = tokens.find(
17962
18339
  (token) => token.start <= offset && offset < token.end
17963
18340
  );
17964
- if (containing?.kind === "identifier") return containing;
18341
+ if (isProjectNameToken(containing)) return containing;
17965
18342
  const touching = tokens.find(
17966
- (token) => token.kind === "identifier" && token.end === offset
18343
+ (token) => isProjectNameToken(token) && token.end === offset
17967
18344
  );
17968
18345
  return touching ?? containing;
17969
18346
  }
18347
+ function isProjectNameToken(token) {
18348
+ return token !== void 0 && (token.kind === "identifier" || token.kind === "type" || token.kind === "keyword");
18349
+ }
17970
18350
  function projectTokens(document) {
17971
18351
  const cached = PROJECT_TOKEN_CACHE.get(document);
17972
18352
  if (cached) return cached;
@@ -18129,7 +18509,7 @@ function collectGlobalChildEntries(sourceText, declaration) {
18129
18509
  continue;
18130
18510
  }
18131
18511
  const name = tokens[index + 1];
18132
- if ((token.kind === "type" || token.kind === "identifier") && name?.kind === "identifier" && tokens[index + 2]?.text === "=" && tokens[index + 3]?.text !== "=" && // A pending annotation or statement boundary precedes a declaration;
18512
+ if ((token.kind === "type" || token.kind === "identifier") && isProjectNameToken(name) && isValidNeoProjectMemberIdentifier(name.text) && tokens[index + 2]?.text === "=" && tokens[index + 3]?.text !== "=" && // A pending annotation or statement boundary precedes a declaration;
18133
18513
  // `key: value` fields and expression member accesses never do.
18134
18514
  tokens[index - 1]?.text !== "." && tokens[index - 1]?.text !== ":") {
18135
18515
  entries.push({
@@ -18184,6 +18564,7 @@ var init_project_source_registry = __esm({
18184
18564
  "../packages/neoscript-language/src/project-source-registry.ts"() {
18185
18565
  "use strict";
18186
18566
  init_lexer();
18567
+ init_project_source_identifiers();
18187
18568
  init_project_source_tokens();
18188
18569
  }
18189
18570
  });
@@ -22133,6 +22514,11 @@ function collectIdentifierReads(expression, names) {
22133
22514
  walk(node.left, visible);
22134
22515
  walk(node.right, visible);
22135
22516
  return;
22517
+ case "conditional":
22518
+ walk(node.condition, visible);
22519
+ walk(node.whenTrue, visible);
22520
+ walk(node.whenFalse, visible);
22521
+ return;
22136
22522
  case "unary":
22137
22523
  case "force":
22138
22524
  case "is":
@@ -23170,6 +23556,50 @@ function validateExpression(expression, expected, scope, environment, uri, range
23170
23556
  );
23171
23557
  return;
23172
23558
  }
23559
+ if (expression.kind === "conditional") {
23560
+ validateExpression(
23561
+ expression.condition,
23562
+ primitiveType("bool"),
23563
+ scope,
23564
+ environment,
23565
+ uri,
23566
+ range2,
23567
+ diagnostics,
23568
+ anchor
23569
+ );
23570
+ const trueType = inferExpressionType2(
23571
+ expression.whenTrue,
23572
+ scope,
23573
+ environment
23574
+ );
23575
+ const falseType = inferExpressionType2(
23576
+ expression.whenFalse,
23577
+ scope,
23578
+ environment
23579
+ );
23580
+ const branchType = expected ?? commonSemanticAssignableType(trueType, falseType);
23581
+ validateExpression(
23582
+ expression.whenTrue,
23583
+ branchType,
23584
+ scope,
23585
+ environment,
23586
+ uri,
23587
+ range2,
23588
+ diagnostics,
23589
+ anchor
23590
+ );
23591
+ validateExpression(
23592
+ expression.whenFalse,
23593
+ branchType,
23594
+ scope,
23595
+ environment,
23596
+ uri,
23597
+ range2,
23598
+ diagnostics,
23599
+ anchor
23600
+ );
23601
+ return;
23602
+ }
23173
23603
  if (expression.kind === "new") {
23174
23604
  const typeName = expression.className ?? expected?.name;
23175
23605
  const declaration = typeName ? environment.types.get(typeName) : void 0;
@@ -23478,13 +23908,19 @@ function substituteSemanticType(type, bindings) {
23478
23908
  return { ...type, arguments: argumentsList2 };
23479
23909
  }
23480
23910
  function semanticTypesAssignable(actual, expected) {
23481
- if (actual.name === expected.name) return true;
23911
+ if (actual.name === "null") {
23912
+ return expected.name === "null" || expected.nullable === true;
23913
+ }
23914
+ if (expected.name === "null") return false;
23915
+ if (actual.name === expected.name) {
23916
+ return actual.nullable !== true || expected.nullable === true;
23917
+ }
23482
23918
  if (actual.name === "void") return false;
23483
23919
  if (actual.name === "int" && (expected.name === "float" || expected.name === "decimal")) {
23484
- return true;
23920
+ return actual.nullable !== true || expected.nullable === true;
23485
23921
  }
23486
23922
  if (actual.name === "float" && expected.name === "decimal") {
23487
- return true;
23923
+ return actual.nullable !== true || expected.nullable === true;
23488
23924
  }
23489
23925
  if (Object.prototype.hasOwnProperty.call(
23490
23926
  NEO_PROJECT_SOURCE_RECORD_CONTRACT.enums,
@@ -23492,12 +23928,42 @@ function semanticTypesAssignable(actual, expected) {
23492
23928
  )) {
23493
23929
  return false;
23494
23930
  }
23495
- const primitiveNames = /* @__PURE__ */ new Set(["bool", "int", "float", "decimal", "string"]);
23496
- if (primitiveNames.has(expected.name) && primitiveNames.has(actual.name)) {
23931
+ if (SEMANTIC_PRIMITIVE_TYPE_NAMES.has(expected.name) && SEMANTIC_PRIMITIVE_TYPE_NAMES.has(actual.name)) {
23497
23932
  return false;
23498
23933
  }
23499
23934
  return true;
23500
23935
  }
23936
+ function commonSemanticAssignableType(left, right) {
23937
+ if (left === void 0) return right;
23938
+ if (right === void 0) return left;
23939
+ if (left.name === "null" && right.name === "null") return left;
23940
+ if (left.name === "null") return { ...right, nullable: true };
23941
+ if (right.name === "null") return { ...left, nullable: true };
23942
+ if (left.name === right.name) {
23943
+ return {
23944
+ ...left,
23945
+ nullable: left.nullable === true || right.nullable === true
23946
+ };
23947
+ }
23948
+ const leftRank = semanticNumericRank(left.name);
23949
+ const rightRank = semanticNumericRank(right.name);
23950
+ if (leftRank !== void 0 && rightRank !== void 0) {
23951
+ const name = leftRank >= rightRank ? left.name : right.name;
23952
+ return {
23953
+ name,
23954
+ nullable: left.nullable === true || right.nullable === true
23955
+ };
23956
+ }
23957
+ if (semanticTypesAssignable(left, right)) return right;
23958
+ if (semanticTypesAssignable(right, left)) return left;
23959
+ return void 0;
23960
+ }
23961
+ function semanticNumericRank(name) {
23962
+ if (name === "int") return 0;
23963
+ if (name === "float") return 1;
23964
+ if (name === "decimal") return 2;
23965
+ return void 0;
23966
+ }
23501
23967
  function describeType(type) {
23502
23968
  const argumentsList2 = type.arguments?.length ? `<${type.arguments.map(describeType).join(", ")}>` : "";
23503
23969
  return `${type.name}${argumentsList2}${type.nullable ? "?" : ""}`;
@@ -23541,10 +24007,24 @@ function inferExpressionType2(expression, scope, environment) {
23541
24007
  if (expression.kind === "litBool") return primitiveType("bool");
23542
24008
  if (expression.kind === "litInt") return primitiveType("int");
23543
24009
  if (expression.kind === "litFloat") return primitiveType("float");
24010
+ if (expression.kind === "litNull") return { name: "null", nullable: true };
23544
24011
  if (expression.kind === "litString" || expression.kind === "litInterp" || expression.kind === "litTripleString")
23545
24012
  return primitiveType("string");
23546
24013
  if (expression.kind === "new")
23547
24014
  return expression.className ? { name: expression.className } : void 0;
24015
+ if (expression.kind === "conditional") {
24016
+ const whenTrue = inferExpressionType2(
24017
+ expression.whenTrue,
24018
+ scope,
24019
+ environment
24020
+ );
24021
+ const whenFalse = inferExpressionType2(
24022
+ expression.whenFalse,
24023
+ scope,
24024
+ environment
24025
+ );
24026
+ return commonSemanticAssignableType(whenTrue, whenFalse);
24027
+ }
23548
24028
  if (expression.kind === "member") {
23549
24029
  if (expression.receiver.kind === "ident" && environment.enums.has(expression.receiver.name)) {
23550
24030
  return { name: expression.receiver.name };
@@ -23869,7 +24349,7 @@ function memberKeyArgument(annotation2) {
23869
24349
  if (argument2 === void 0) return null;
23870
24350
  const text = argument2.text.trim();
23871
24351
  return {
23872
- key: IDENTIFIER_PATTERN2.test(text) ? text : null,
24352
+ key: IDENTIFIER_PATTERN.test(text) ? text : null,
23873
24353
  range: argument2.range
23874
24354
  };
23875
24355
  }
@@ -24058,7 +24538,7 @@ function classDerivesFromName(name, ancestorName, environment, seen = /* @__PURE
24058
24538
  return classDerivesFromName(base.name, ancestorName, environment, seen);
24059
24539
  });
24060
24540
  }
24061
- var NEO_VARIANT_FOLDER_SETTING, primitiveType, IDENTIFIER_PATTERN2, LIST_COLUMN_INHERITANCE_KEY;
24541
+ var NEO_VARIANT_FOLDER_SETTING, primitiveType, IDENTIFIER_PATTERN, LIST_COLUMN_INHERITANCE_KEY, SEMANTIC_PRIMITIVE_TYPE_NAMES;
24062
24542
  var init_project_source_semantics = __esm({
24063
24543
  "../packages/neoscript-language/src/project-source-semantics.ts"() {
24064
24544
  "use strict";
@@ -24073,8 +24553,15 @@ var init_project_source_semantics = __esm({
24073
24553
  init_project_root();
24074
24554
  NEO_VARIANT_FOLDER_SETTING = "folder";
24075
24555
  primitiveType = (name) => ({ name });
24076
- IDENTIFIER_PATTERN2 = /^[A-Za-z_][A-Za-z0-9_]*$/;
24556
+ IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
24077
24557
  LIST_COLUMN_INHERITANCE_KEY = "__other__";
24558
+ SEMANTIC_PRIMITIVE_TYPE_NAMES = /* @__PURE__ */ new Set([
24559
+ "bool",
24560
+ "int",
24561
+ "float",
24562
+ "decimal",
24563
+ "string"
24564
+ ]);
24078
24565
  }
24079
24566
  });
24080
24567
 
@@ -27047,14 +27534,16 @@ function collectFlowSymbols(uri, content, ownerName, scopeRange, symbols, diagno
27047
27534
  }
27048
27535
  }
27049
27536
  function collectSymbol(uri, kind, name, range2, annotations, ownerName, symbols, diagnostics, scopeRange, detail, callable2, documentation, staticMember) {
27050
- if (isNeoProjectReservedName(name)) {
27537
+ const memberLabel2 = kind === "member" || kind === "enumOption" || kind === "graphChild";
27538
+ const reserved = memberLabel2 ? isNeoProjectMemberReservedName(name) : isNeoProjectReservedName(name);
27539
+ if (reserved) {
27051
27540
  diagnostics.push({
27052
27541
  uri,
27053
27542
  range: range2,
27054
27543
  severity: "error",
27055
27544
  source: "neo-project",
27056
27545
  code: "reserved-project-name",
27057
- message: `'${name}' is a reserved Neo keyword and cannot be used as a persisted source name without the language's identifier escape syntax.`
27546
+ message: `'${name}' is reserved in this Neo declaration context and cannot be used as a persisted source name without the language's identifier escape syntax.`
27058
27547
  });
27059
27548
  }
27060
27549
  const id2 = sourceId(uri, annotations, diagnostics);
@@ -28523,7 +29012,7 @@ function projectVariantScopeCompletion(analysis, document, position) {
28523
29012
  }
28524
29013
  function projectVariantPathSymbolAt(analysis, document, position) {
28525
29014
  const token = projectTokenAt(document, position);
28526
- if (!token || token.kind !== "identifier") return null;
29015
+ if (!isProjectNameToken(token)) return null;
28527
29016
  const tokens = projectTokens(document);
28528
29017
  const tokenIndex = tokens.findIndex(
28529
29018
  (candidate) => candidate.start === token.start && candidate.end === token.end
@@ -28534,7 +29023,7 @@ function projectVariantPathSymbolAt(analysis, document, position) {
28534
29023
  for (; ; ) {
28535
29024
  const dot = tokens[cursor];
28536
29025
  const owner = tokens[cursor - 1];
28537
- if (dot?.text !== "." || owner?.kind !== "identifier") break;
29026
+ if (dot?.text !== "." || !isProjectNameToken(owner)) break;
28538
29027
  segments.unshift(owner.text);
28539
29028
  cursor -= 2;
28540
29029
  }
@@ -29187,10 +29676,12 @@ function projectSemanticTokens(document, analysis) {
29187
29676
  return [];
29188
29677
  }
29189
29678
  const declaration = symbolsDeclaredAt(index, document.uri, token.range)[0];
29190
- const resolved = token.kind === "identifier" ? indexedProjectSymbolAt(analysis, document, token.range.start, index)?.symbol : void 0;
29679
+ const resolved = isProjectNameToken(token) ? indexedProjectSymbolAt(analysis, document, token.range.start, index)?.symbol : void 0;
29191
29680
  let type;
29192
29681
  if (declaration) {
29193
29682
  type = projectSemanticTokenType(declaration);
29683
+ } else if (resolved) {
29684
+ type = projectSemanticTokenType(resolved);
29194
29685
  } else if (token.kind === "keyword") type = "keyword";
29195
29686
  else if (token.kind === "type") type = "type";
29196
29687
  else if (token.kind === "string") type = "string";
@@ -29242,7 +29733,14 @@ function projectSymbolAt(analysis, document, position) {
29242
29733
  }
29243
29734
  function indexedProjectSymbolAt(analysis, document, position, index) {
29244
29735
  const token = projectTokenAt(document, position);
29245
- if (!token || token.kind !== "identifier") return null;
29736
+ if (!isProjectNameToken(token)) return null;
29737
+ const body = projectBodySnapshotAt(analysis, document, position);
29738
+ if (body) {
29739
+ const reference2 = referenceAtPosition(body, position);
29740
+ const symbolId = reference2 ? resolveReferenceSymbolId(body, reference2) : null;
29741
+ const symbol = symbolId ? analysis.symbols.find((candidate) => candidate.id === symbolId) : void 0;
29742
+ if (symbol) return { token, symbol };
29743
+ }
29246
29744
  const exact = symbolsDeclaredAt(index, document.uri, token.range);
29247
29745
  if (exact.length === 1) return { token, symbol: exact[0] };
29248
29746
  const candidates = index.byName.get(token.text) ?? [];
@@ -29299,7 +29797,7 @@ function indexedProjectSymbolAt(analysis, document, position, index) {
29299
29797
  dotOwner.range.start,
29300
29798
  index
29301
29799
  );
29302
- const ownerNames = resolvedOwner ? projectReceiverOwnerNames(analysis, resolvedOwner.symbol) : [dotOwner.text];
29800
+ const ownerNames = dotOwner.text === "this" && owner ? projectTypeAndBaseOwnerNames(analysis, owner) : resolvedOwner ? projectReceiverOwnerNames(analysis, resolvedOwner.symbol) : [dotOwner.text];
29303
29801
  const qualified = visibleCandidates.filter(
29304
29802
  (symbol) => symbol.ownerName !== void 0 && ownerNames.includes(symbol.ownerName) && (resolvedOwner === null || projectQualifiedSymbolMatchesReceiver(symbol, resolvedOwner.symbol))
29305
29803
  );
@@ -29334,27 +29832,33 @@ function projectQualifiedSymbolMatchesReceiver(symbol, receiver) {
29334
29832
  }
29335
29833
  function projectReceiverOwnerNames(analysis, receiver) {
29336
29834
  const result = [];
29337
- const visitedTypes = /* @__PURE__ */ new Set();
29338
- const appendTypeAndBases = (typeName2) => {
29339
- if (visitedTypes.has(typeName2)) return;
29340
- visitedTypes.add(typeName2);
29341
- if (!result.includes(typeName2)) result.push(typeName2);
29342
- const declaration = findTypeDeclaration(analysis, typeName2);
29835
+ if (receiver.kind === "global") {
29836
+ result.push(receiver.name);
29837
+ }
29838
+ const typeName = projectSymbolTypeName(receiver);
29839
+ if (typeName)
29840
+ result.push(...projectTypeAndBaseOwnerNames(analysis, typeName));
29841
+ return result;
29842
+ }
29843
+ function projectTypeAndBaseOwnerNames(analysis, typeName) {
29844
+ const result = [];
29845
+ const visited = /* @__PURE__ */ new Set();
29846
+ const append = (candidateName) => {
29847
+ if (visited.has(candidateName)) return;
29848
+ visited.add(candidateName);
29849
+ result.push(candidateName);
29850
+ const declaration = findTypeDeclaration(analysis, candidateName);
29343
29851
  if (declaration?.kind !== "class" && declaration?.kind !== "interface") {
29344
29852
  return;
29345
29853
  }
29346
29854
  for (const base of declaration.baseTypes) {
29347
29855
  const resolved = findTypeDeclaration(analysis, base.name);
29348
29856
  if (resolved?.kind === "class" || resolved?.kind === "interface") {
29349
- appendTypeAndBases(base.name);
29857
+ append(base.name);
29350
29858
  }
29351
29859
  }
29352
29860
  };
29353
- if (receiver.kind === "global") {
29354
- result.push(receiver.name);
29355
- }
29356
- const typeName = projectSymbolTypeName(receiver);
29357
- if (typeName) appendTypeAndBases(typeName);
29861
+ append(typeName);
29358
29862
  return result;
29359
29863
  }
29360
29864
  function contextualProjectEnumOptionSymbol(analysis, document, token, candidates, source) {
@@ -33099,6 +33603,8 @@ var init_service = __esm({
33099
33603
  init_analyzer();
33100
33604
  init_compiler();
33101
33605
  init_formatter();
33606
+ init_generated_csharp_identifiers();
33607
+ init_project_source_identifiers();
33102
33608
  init_project_source_analysis();
33103
33609
  init_project_source_construction_quick_fixes();
33104
33610
  init_project_source_language_features();
@@ -33320,9 +33826,25 @@ var init_service = __esm({
33320
33826
  return { range: reference2.range, placeholder: reference2.name };
33321
33827
  }
33322
33828
  rename(uri, position, newName) {
33323
- if (!isValidRenameIdentifier(newName)) {
33829
+ const state = this.requireState(uri);
33830
+ let validName;
33831
+ if (isProjectDocument(state.document, state.context)) {
33832
+ const resolved = projectSymbolAt(
33833
+ this.projectAnalysis(),
33834
+ state.document,
33835
+ position
33836
+ );
33837
+ if (!resolved) return null;
33838
+ const memberLabel2 = resolved.symbol.kind === "member" || resolved.symbol.kind === "enumOption" || resolved.symbol.kind === "graphChild";
33839
+ const binding = resolved.symbol.kind === "parameter" || resolved.symbol.kind === "genericParameter" || resolved.symbol.kind === "flowBinding";
33840
+ const validNeoName = memberLabel2 ? isValidNeoProjectMemberIdentifier(newName) : binding ? isValidNeoProjectBindingIdentifier(newName) : isValidNeoProjectIdentifier(newName);
33841
+ validName = validNeoName && isGeneratedCSharpIdentifier(newName) && !isGeneratedCSharpReservedKeyword(newName);
33842
+ } else {
33843
+ validName = isValidNeoScriptBindingIdentifier(newName);
33844
+ }
33845
+ if (!validName) {
33324
33846
  throw new Error(
33325
- `Cannot rename a NeoScript symbol to "${newName}": use a non-keyword identifier containing letters, digits, or underscores.`
33847
+ `Cannot rename a NeoScript symbol to "${newName}": use an identifier valid in this declaration context and generated C#.`
33326
33848
  );
33327
33849
  }
33328
33850
  const prepared = this.prepareRename(uri, position);
@@ -33422,7 +33944,7 @@ var init_service = __esm({
33422
33944
  }
33423
33945
  projectReferences(document, position, includeDeclaration) {
33424
33946
  const token = projectTokenAt(document, position);
33425
- if (!token || token.kind !== "identifier") return [];
33947
+ if (!isProjectNameToken(token)) return [];
33426
33948
  const analysis = this.projectAnalysis();
33427
33949
  const resolved = projectSymbolAt(analysis, document, position);
33428
33950
  if (!resolved) return [];
@@ -33431,7 +33953,7 @@ var init_service = __esm({
33431
33953
  for (const state of this.documents.values()) {
33432
33954
  if (!isProjectDocument(state.document, state.context)) continue;
33433
33955
  for (const candidate of projectTokens(state.document)) {
33434
- if (candidate.kind !== "identifier" || candidate.text !== token.text) {
33956
+ if (!isProjectNameToken(candidate) || candidate.text !== token.text) {
33435
33957
  continue;
33436
33958
  }
33437
33959
  const candidateSymbol = projectSymbolAt(
@@ -41184,6 +41706,46 @@ var init_docs_text2 = __esm({
41184
41706
  }
41185
41707
  });
41186
41708
 
41709
+ // ../src/models/project-source-identifiers.ts
41710
+ function isValidGeneratedIdentifier(value) {
41711
+ return typeof value === "string" && isGeneratedCSharpIdentifier(value) && !isGeneratedCSharpReservedKeyword(value);
41712
+ }
41713
+ function isValidProjectSourceIdentifier(value) {
41714
+ return isValidGeneratedIdentifier(value) && isValidNeoProjectIdentifier(value);
41715
+ }
41716
+ function isValidProjectMemberIdentifier(value) {
41717
+ return isValidGeneratedIdentifier(value) && isValidNeoProjectMemberIdentifier(value);
41718
+ }
41719
+ function isValidProjectBindingIdentifier(value) {
41720
+ return isValidGeneratedIdentifier(value) && isValidNeoProjectBindingIdentifier(value);
41721
+ }
41722
+ var init_project_source_identifiers2 = __esm({
41723
+ "../src/models/project-source-identifiers.ts"() {
41724
+ "use strict";
41725
+ init_src();
41726
+ }
41727
+ });
41728
+
41729
+ // ../src/models/schema-identifiers.ts
41730
+ function isValidSchemaAuthoredIdentifier(value) {
41731
+ return isValidProjectSourceIdentifier(value);
41732
+ }
41733
+ function isValidSchemaMemberIdentifier(value) {
41734
+ return isValidProjectMemberIdentifier(value);
41735
+ }
41736
+ function isValidSchemaBindingIdentifier(value) {
41737
+ return isValidProjectBindingIdentifier(value);
41738
+ }
41739
+ function isValidSchemaNSFunctionBindingIdentifier(value) {
41740
+ return isValidSchemaBindingIdentifier(value) && value !== "value";
41741
+ }
41742
+ var init_schema_identifiers = __esm({
41743
+ "../src/models/schema-identifiers.ts"() {
41744
+ "use strict";
41745
+ init_project_source_identifiers2();
41746
+ }
41747
+ });
41748
+
41187
41749
  // ../src/models/neoscript/neoscript-types.ts
41188
41750
  var NS_TYPE_UNKNOWN, NS_TYPE_VOID, NSAssignmentOperator, NSWritability, NSCollectionMutation;
41189
41751
  var init_neoscript_types = __esm({
@@ -41568,6 +42130,32 @@ function isNSPointerCoalesce(value) {
41568
42130
  if (!isNSPointer(v.left)) return false;
41569
42131
  return isNSPointer(v.right);
41570
42132
  }
42133
+ function isNSPointerConditional(value) {
42134
+ if (typeof value !== "object" || value === null) return false;
42135
+ if (!("type" in value) || value.type !== "conditional" /* conditional */) {
42136
+ return false;
42137
+ }
42138
+ if (!("condition" in value) || !isNSPointer(value.condition)) return false;
42139
+ if (!("whenTrue" in value) || !isNSPointer(value.whenTrue)) return false;
42140
+ return "whenFalse" in value && isNSPointer(value.whenFalse);
42141
+ }
42142
+ function isNSPointerDelegateClosure(value) {
42143
+ if (typeof value !== "object" || value === null) return false;
42144
+ if (!("type" in value) || value.type !== "delegateClosure" /* delegateClosure */) {
42145
+ return false;
42146
+ }
42147
+ if (!("typeInfo" in value) || !isNSTypeInfo(value.typeInfo) || value.typeInfo.type !== 25 /* NSDelegate */) {
42148
+ return false;
42149
+ }
42150
+ if (!("action" in value) || !isNSFunctionWithReturnType(value.action)) {
42151
+ return false;
42152
+ }
42153
+ if (!("captures" in value) || !Array.isArray(value.captures) || !value.captures.every(isNSPointer)) {
42154
+ return false;
42155
+ }
42156
+ if (!("code" in value) || value.code === void 0) return true;
42157
+ return typeof value.code === "string" && value.code.length > 0;
42158
+ }
41571
42159
  function isNSPointerToBool(value) {
41572
42160
  const v = value;
41573
42161
  if (v?.type !== "toBool" /* toBool */) return false;
@@ -41595,6 +42183,12 @@ function isNSPointerCallFunction(value) {
41595
42183
  if (v.optional !== void 0 && typeof v.optional !== "boolean") {
41596
42184
  return false;
41597
42185
  }
42186
+ if (v.missingMemberFallback !== void 0 && v.missingMemberFallback !== "valueEquality") {
42187
+ return false;
42188
+ }
42189
+ if (v.missingMemberFallback === "valueEquality" && (!hasMemberKey || v.receiver?.kind !== "instance" || v.args.length !== 1)) {
42190
+ return false;
42191
+ }
41598
42192
  return true;
41599
42193
  }
41600
42194
  function isNSPointerCallDelegate(value) {
@@ -41635,7 +42229,7 @@ function isNSPointerFunctionErrorCheck(value) {
41635
42229
  return isNSFunctionErrorCheckMode(v.mode);
41636
42230
  }
41637
42231
  function isNSPointer(value) {
41638
- return isNSPointerReference(value) || isNSPointerVariable(value) || isNSPointerStaticMember(value) || isNSPointerValue(value) || isNSPointerOperation(value) || isNSPointerFunction(value) || isNSPointerKeyOf(value) || isNSPointerListLiteral(value) || isNSPointerDictLiteral(value) || isNSPointerForceUnwrap(value) || isNSPointerIsCheck(value) || isNSPointerCallGetter(value) || isNSPointerCoalesce(value) || isNSPointerToBool(value) || isNSPointerStringify(value) || isNSPointerCallFunction(value) || isNSPointerCallDelegate(value) || isNSPointerCallAction(value) || isNSPointerVariant(value) || isNSPointerFunctionErrorCheck(value);
42232
+ return isNSPointerReference(value) || isNSPointerVariable(value) || isNSPointerStaticMember(value) || isNSPointerValue(value) || isNSPointerOperation(value) || isNSPointerFunction(value) || isNSPointerKeyOf(value) || isNSPointerListLiteral(value) || isNSPointerDictLiteral(value) || isNSPointerForceUnwrap(value) || isNSPointerIsCheck(value) || isNSPointerCallGetter(value) || isNSPointerCoalesce(value) || isNSPointerConditional(value) || isNSPointerDelegateClosure(value) || isNSPointerToBool(value) || isNSPointerStringify(value) || isNSPointerCallFunction(value) || isNSPointerCallDelegate(value) || isNSPointerCallAction(value) || isNSPointerVariant(value) || isNSPointerFunctionErrorCheck(value);
41639
42233
  }
41640
42234
  function isNSPointers(value) {
41641
42235
  return Array.isArray(value) && value.every(isNSPointer);
@@ -41704,24 +42298,7 @@ function isNSFunctionWithReturnType(value) {
41704
42298
  if (!Array.isArray(v.parameters)) return false;
41705
42299
  if (!v.parameters.every(isNSVariable)) return false;
41706
42300
  if (!isNSInstructions(v.instructions)) return false;
41707
- if ([
41708
- "for" /* for */,
41709
- "forEach" /* forEach */,
41710
- "break" /* break */,
41711
- "continue" /* continue */
41712
- ].some((type) => nsInstructionsContainType(v.instructions ?? [], type)) && (v.compilerRevision ?? 1) < 4) {
41713
- return false;
41714
- }
41715
- if (nsInstructionsContainType(v.instructions, "switch" /* switch */) && (v.compilerRevision ?? 1) < 5) {
41716
- return false;
41717
- }
41718
- if (nsInstructionsContainType(v.instructions, "try" /* try */) && (v.compilerRevision ?? 1) < 6) {
41719
- return false;
41720
- }
41721
- if ((v.compilerRevision ?? 1) < 8 && ([
41722
- "addActionListener" /* addActionListener */,
41723
- "removeActionListener" /* removeActionListener */
41724
- ].some((type) => nsInstructionsContainType(v.instructions ?? [], type)) || nsIRContainsPointerType(v.instructions, "callAction" /* callAction */))) {
42301
+ if ((v.compilerRevision ?? 1) < NEOSCRIPT_COMPILER_REVISION && (v.compilerRevision ?? 1) < minimumNeoScriptCompilerRevisionForIR(v.instructions)) {
41725
42302
  return false;
41726
42303
  }
41727
42304
  if (!isNSTypeInfo(v.typeInfo)) return false;
@@ -42162,44 +42739,32 @@ function isNSInstructionTry(value) {
42162
42739
  function isNSInstruction(value) {
42163
42740
  return isNSInstructionVariable(value) || isNSInstructionIfBranch(value) || isNSInstructionReturn(value) || isNSInstructionThrow(value) || isNSInstructionAssign(value) || isNSInstructionCollectionCall(value) || isNSInstructionFunctionCall(value) || isNSInstructionFor(value) || isNSInstructionForEach(value) || isNSInstructionBreak(value) || isNSInstructionContinue(value) || isNSInstructionSwitch(value) || isNSInstructionTry(value) || isNSInstructionAddActionListener(value) || isNSInstructionRemoveActionListener(value);
42164
42741
  }
42165
- function nsInstructionsContainType(instructions, type) {
42166
- return instructions.some((instruction) => {
42167
- if (instruction.type === type) return true;
42168
- if (instruction.type === "if" /* if */) {
42169
- return instruction.branches.some(
42170
- (branch) => nsInstructionsContainType(branch.instructions, type)
42171
- ) || instruction.else !== null && instruction.else !== void 0 && nsInstructionsContainType(instruction.else, type);
42172
- }
42173
- if (instruction.type === "for" /* for */ || instruction.type === "forEach" /* forEach */) {
42174
- return nsInstructionsContainType(instruction.instructions, type);
42175
- }
42176
- if (instruction.type === "switch" /* switch */) {
42177
- return instruction.sections.some(
42178
- (section) => nsInstructionsContainType(section.instructions, type)
42179
- ) || instruction.defaultInstructions !== null && instruction.defaultInstructions !== void 0 && nsInstructionsContainType(instruction.defaultInstructions, type);
42180
- }
42181
- if (instruction.type === "try" /* try */) {
42182
- return nsInstructionsContainType(instruction.instructions, type) || instruction.catches.some(
42183
- (clause) => nsInstructionsContainType(clause.instructions, type)
42742
+ function minimumNeoScriptCompilerRevisionForIR(node, visited = /* @__PURE__ */ new Set()) {
42743
+ if (Array.isArray(node)) {
42744
+ let minimum2 = 1;
42745
+ for (const entry of node) {
42746
+ minimum2 = Math.max(
42747
+ minimum2,
42748
+ minimumNeoScriptCompilerRevisionForIR(entry, visited)
42184
42749
  );
42185
42750
  }
42186
- return false;
42187
- });
42188
- }
42189
- function nsIRContainsPointerType(node, type, visited = /* @__PURE__ */ new Set()) {
42190
- if (Array.isArray(node)) {
42191
- return node.some((entry) => nsIRContainsPointerType(entry, type, visited));
42751
+ return minimum2;
42192
42752
  }
42193
- if (typeof node !== "object" || node === null) return false;
42194
- if (visited.has(node)) return false;
42753
+ if (typeof node !== "object" || node === null) return 1;
42754
+ if (visited.has(node)) return 1;
42195
42755
  visited.add(node);
42196
- const record3 = node;
42197
- if (record3.type === type) return true;
42198
- const isLiteralValue = "typeInfo" in record3 && "value" in record3 && !("type" in record3);
42199
- return Object.entries(record3).some(([key, child]) => {
42200
- if (isLiteralValue && key === "value") return false;
42201
- return nsIRContainsPointerType(child, type, visited);
42202
- });
42756
+ const discriminatorRevision = "type" in node && typeof node.type === "string" ? MINIMUM_REVISION_BY_IR_DISCRIMINATOR.get(node.type) ?? 1 : 1;
42757
+ const fallbackRevision = "missingMemberFallback" in node && node.missingMemberFallback === "valueEquality" ? 12 : 1;
42758
+ let minimum = Math.max(discriminatorRevision, fallbackRevision);
42759
+ const isLiteralValue = "typeInfo" in node && "value" in node && !("type" in node);
42760
+ for (const [key, child] of Object.entries(node)) {
42761
+ if (isLiteralValue && key === "value") continue;
42762
+ minimum = Math.max(
42763
+ minimum,
42764
+ minimumNeoScriptCompilerRevisionForIR(child, visited)
42765
+ );
42766
+ }
42767
+ return minimum;
42203
42768
  }
42204
42769
  function isNSInstructions(value) {
42205
42770
  return Array.isArray(value) && value.every(isNSInstruction);
@@ -42247,7 +42812,7 @@ function isNSVoidBody(value) {
42247
42812
  if (value.typeInfo.type !== 0 /* Null */) return false;
42248
42813
  return value.typeInfo.required === true;
42249
42814
  }
42250
- var NS_STRING_OPS, NS_DECIMAL_OPS, NS_MATH_OPS;
42815
+ var NS_STRING_OPS, NS_DECIMAL_OPS, NS_MATH_OPS, MINIMUM_REVISION_BY_IR_DISCRIMINATOR;
42251
42816
  var init_neoscript_guards = __esm({
42252
42817
  "../src/models/neoscript/neoscript-guards.ts"() {
42253
42818
  "use strict";
@@ -42280,6 +42845,20 @@ var init_neoscript_guards = __esm({
42280
42845
  "sign",
42281
42846
  "sqrt"
42282
42847
  ];
42848
+ MINIMUM_REVISION_BY_IR_DISCRIMINATOR = /* @__PURE__ */ new Map([
42849
+ ["for" /* for */, 4],
42850
+ ["forEach" /* forEach */, 4],
42851
+ ["break" /* break */, 4],
42852
+ ["continue" /* continue */, 4],
42853
+ ["switch" /* switch */, 5],
42854
+ ["try" /* try */, 6],
42855
+ ["callDelegate" /* callDelegate */, 7],
42856
+ ["addActionListener" /* addActionListener */, 8],
42857
+ ["removeActionListener" /* removeActionListener */, 8],
42858
+ ["callAction" /* callAction */, 8],
42859
+ ["conditional" /* conditional */, 12],
42860
+ ["delegateClosure" /* delegateClosure */, 12]
42861
+ ]);
42283
42862
  }
42284
42863
  });
42285
42864
 
@@ -42755,12 +43334,20 @@ function isMemberAccessModifierKind(value) {
42755
43334
  if (value === "protected") return true;
42756
43335
  return value === "private";
42757
43336
  }
42758
- function isValidCallableIdentifier(value) {
42759
- if (typeof value !== "string") return false;
42760
- if (!FunctionMemberNamePattern.test(value)) return false;
43337
+ function isValidCallableMemberIdentifier(value) {
43338
+ if (!isValidSchemaMemberIdentifier(value)) return false;
43339
+ if (value.startsWith("__")) return false;
43340
+ return true;
43341
+ }
43342
+ function isValidCallableArgumentIdentifier(value) {
43343
+ if (!isValidSchemaBindingIdentifier(value)) return false;
42761
43344
  if (value.startsWith("__")) return false;
42762
43345
  return !FunctionArgumentReservedNames.has(value);
42763
43346
  }
43347
+ function isValidNSFunctionArgumentIdentifier(value) {
43348
+ if (!isValidSchemaNSFunctionBindingIdentifier(value)) return false;
43349
+ return !value.startsWith("__");
43350
+ }
42764
43351
  function isMemberListColumnSettings(value) {
42765
43352
  if (!value) return false;
42766
43353
  if (typeof value !== "object") return false;
@@ -43124,7 +43711,7 @@ function isMemberAudioBase(value) {
43124
43711
  function isMemberFunctionBase(value) {
43125
43712
  const v = asMemberBaseForKind(value, 13 /* Function */);
43126
43713
  if (v === null) return false;
43127
- if (!isValidCallableIdentifier(v.name)) return false;
43714
+ if (!isValidCallableMemberIdentifier(v.name)) return false;
43128
43715
  if (!isNSFunctionReturnTypeInfo(v.returnTypeInfo)) return false;
43129
43716
  if (!Array.isArray(v.argumentTypes)) return false;
43130
43717
  if (typeof v.deferred !== "boolean") return false;
@@ -43132,7 +43719,7 @@ function isMemberFunctionBase(value) {
43132
43719
  const argumentTypes = [];
43133
43720
  for (const arg of v.argumentTypes) {
43134
43721
  if (!isNSFunctionArgumentTypeInfo(arg)) return false;
43135
- if (!isValidCallableIdentifier(arg.name)) return false;
43722
+ if (!isValidCallableArgumentIdentifier(arg.name)) return false;
43136
43723
  if (arg.type === NS_TYPE_UNKNOWN) return false;
43137
43724
  if (names.has(arg.name)) return false;
43138
43725
  names.add(arg.name);
@@ -43178,7 +43765,7 @@ function isNSFunctionUIBody(value) {
43178
43765
  function isMemberNSFunctionBase(value) {
43179
43766
  const v = asMemberBaseForKind(value, 23 /* NSFunction */);
43180
43767
  if (v === null) return false;
43181
- if (!isValidCallableIdentifier(v.name)) return false;
43768
+ if (!isValidCallableMemberIdentifier(v.name)) return false;
43182
43769
  if (v.required !== false) return false;
43183
43770
  if (v.defaultValue !== void 0 && v.defaultValue !== null) return false;
43184
43771
  if (v.storage !== void 0 && v.storage !== null) return false;
@@ -43194,8 +43781,7 @@ function isMemberNSFunctionBase(value) {
43194
43781
  for (const argument2 of v.argumentTypes) {
43195
43782
  if (!isNSFunctionArgumentTypeInfo(argument2)) return false;
43196
43783
  if (argument2.type === NS_TYPE_UNKNOWN) return false;
43197
- if (!isValidCallableIdentifier(argument2.name)) return false;
43198
- if (NSFunctionArgumentReservedNames.has(argument2.name)) return false;
43784
+ if (!isValidNSFunctionArgumentIdentifier(argument2.name)) return false;
43199
43785
  if (names.has(argument2.name)) return false;
43200
43786
  names.add(argument2.name);
43201
43787
  argumentTypes.push(argument2);
@@ -43243,11 +43829,18 @@ function isNSDelegateClosureValueDraft(value) {
43243
43829
  function isNSDelegateClosureValue(value) {
43244
43830
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
43245
43831
  const record3 = value;
43246
- const keys = record3.code === void 0 ? ["action"] : ["code", "action"];
43832
+ const keys = [
43833
+ ...record3.code === void 0 ? [] : ["code"],
43834
+ "action",
43835
+ ...record3.captures === void 0 ? [] : ["captures"]
43836
+ ];
43247
43837
  if (!hasExactKeys(record3, keys)) return false;
43248
43838
  if (record3.code !== void 0 && (typeof record3.code !== "string" || record3.code.length === 0)) {
43249
43839
  return false;
43250
43840
  }
43841
+ if (record3.captures !== void 0 && !Array.isArray(record3.captures)) {
43842
+ return false;
43843
+ }
43251
43844
  return isNSFunctionWithReturnType(record3.action);
43252
43845
  }
43253
43846
  function isNSDelegateValue(value) {
@@ -43273,7 +43866,7 @@ function isMemberDelegateBase(value) {
43273
43866
  const names = /* @__PURE__ */ new Set();
43274
43867
  for (const argument2 of v.argumentTypes) {
43275
43868
  if (!isNSFunctionArgumentTypeInfo(argument2)) return false;
43276
- if (!isValidCallableIdentifier(argument2.name)) return false;
43869
+ if (!isValidCallableArgumentIdentifier(argument2.name)) return false;
43277
43870
  if (argument2.type === NS_TYPE_UNKNOWN) return false;
43278
43871
  if (names.has(argument2.name)) return false;
43279
43872
  names.add(argument2.name);
@@ -43312,7 +43905,7 @@ function isMemberActionBase(value) {
43312
43905
  const names = /* @__PURE__ */ new Set();
43313
43906
  for (const argument2 of v.argumentTypes) {
43314
43907
  if (!isNSFunctionArgumentTypeInfo(argument2)) return false;
43315
- if (!isValidCallableIdentifier(argument2.name)) return false;
43908
+ if (!isValidCallableArgumentIdentifier(argument2.name)) return false;
43316
43909
  if (argument2.type === NS_TYPE_UNKNOWN) return false;
43317
43910
  if (names.has(argument2.name)) return false;
43318
43911
  names.add(argument2.name);
@@ -43616,7 +44209,7 @@ function isMemberOverrideProps(value) {
43616
44209
  if (v.setter !== void 0 && !isNSVoidBody(v.setter)) return false;
43617
44210
  const isCallableOverride = v.kind === 13 /* Function */ || v.kind === 23 /* NSFunction */;
43618
44211
  if (isCallableOverride) {
43619
- if (!isValidCallableIdentifier(v.name)) return false;
44212
+ if (!isValidCallableMemberIdentifier(v.name)) return false;
43620
44213
  if (v.returnTypeInfo !== void 0) return false;
43621
44214
  if (v.argumentTypes !== void 0) return false;
43622
44215
  if (v.deferred !== void 0) return false;
@@ -43693,37 +44286,23 @@ function isAnyMember(value) {
43693
44286
  function isAnyMemberAuthoredOrCompiled(value) {
43694
44287
  return isAnyMember(value) || isUncompiledMemberNSFunctionOverride(value);
43695
44288
  }
43696
- var FunctionMemberNamePattern, FunctionArgumentReservedNames, NSFunctionArgumentReservedNames, DECIMAL_STRING_PATTERN, DECIMAL_MAX_SIGNIFICANT_DIGITS, DECIMAL_MAX_SCALE;
44289
+ var FunctionArgumentReservedNames, NSFunctionArgumentReservedNames, DECIMAL_STRING_PATTERN, DECIMAL_MAX_SIGNIFICANT_DIGITS, DECIMAL_MAX_SCALE;
43697
44290
  var init_member_kinds = __esm({
43698
44291
  "../src/models/members/member-kinds.ts"() {
43699
44292
  "use strict";
43700
44293
  init_core();
43701
44294
  init_docs_text2();
44295
+ init_schema_identifiers();
43702
44296
  init_neoscript();
43703
44297
  init_classes();
43704
44298
  init_member_kind_enum();
43705
44299
  init_member_storage();
43706
44300
  init_structured_leaf_fields();
43707
44301
  init_member_kind_enum();
43708
- FunctionMemberNamePattern = /^[A-Za-z_][A-Za-z0-9_]*$/;
43709
44302
  FunctionArgumentReservedNames = /* @__PURE__ */ new Set([
43710
44303
  "this",
43711
44304
  "root",
43712
- "context",
43713
- "true",
43714
- "false",
43715
- "null",
43716
- "void",
43717
- "if",
43718
- "else",
43719
- "return",
43720
- "throw",
43721
- "var",
43722
- "int",
43723
- "float",
43724
- "decimal",
43725
- "string",
43726
- "bool"
44305
+ "context"
43727
44306
  ]);
43728
44307
  NSFunctionArgumentReservedNames = /* @__PURE__ */ new Set([
43729
44308
  ...FunctionArgumentReservedNames,
@@ -47819,28 +48398,6 @@ var init_files = __esm({
47819
48398
  }
47820
48399
  });
47821
48400
 
47822
- // ../src/models/project-source-identifiers.ts
47823
- function isValidProjectSourceIdentifier(value) {
47824
- return typeof value === "string" && isValidNeoProjectIdentifier(value) && isGeneratedCSharpIdentifier(value) && !isGeneratedCSharpReservedKeyword(value);
47825
- }
47826
- var init_project_source_identifiers2 = __esm({
47827
- "../src/models/project-source-identifiers.ts"() {
47828
- "use strict";
47829
- init_src();
47830
- }
47831
- });
47832
-
47833
- // ../src/models/schema-identifiers.ts
47834
- function isValidSchemaAuthoredIdentifier(value) {
47835
- return isValidProjectSourceIdentifier(value);
47836
- }
47837
- var init_schema_identifiers = __esm({
47838
- "../src/models/schema-identifiers.ts"() {
47839
- "use strict";
47840
- init_project_source_identifiers2();
47841
- }
47842
- });
47843
-
47844
48401
  // ../src/models/enum/enum-types.ts
47845
48402
  function isValidEnumOptionId(id2) {
47846
48403
  if (typeof id2 !== "string" || id2.length === 0) return false;
@@ -47852,7 +48409,7 @@ function isProspectiveEnumOptionId(id2) {
47852
48409
  return isValidEnumOptionId(id2);
47853
48410
  }
47854
48411
  function isValidEnumOptionName(name) {
47855
- return isValidSchemaAuthoredIdentifier(name);
48412
+ return isValidSchemaMemberIdentifier(name);
47856
48413
  }
47857
48414
  function isEnumOptionWithIds(value, isOptionId) {
47858
48415
  const v = value;
@@ -50794,14 +51351,14 @@ function listAnnotations(member) {
50794
51351
  if (member.kind !== "list") return [];
50795
51352
  return [
50796
51353
  ...member.indexes.map((entry) => {
50797
- assertIdentifier(entry.schemaKey, "list index member");
51354
+ assertMemberIdentifier(entry.schemaKey, "list index member");
50798
51355
  return `@index(${[
50799
51356
  `member: ${entry.schemaKey}`,
50800
51357
  ...entry.unique ? ["unique: true"] : []
50801
51358
  ].join(", ")})`;
50802
51359
  }),
50803
51360
  ...member.columns.map((entry) => {
50804
- assertIdentifier(entry.memberKey, "list column member");
51361
+ assertMemberIdentifier(entry.memberKey, "list column member");
50805
51362
  return `@column(${[
50806
51363
  `member: ${entry.memberKey}`,
50807
51364
  ...entry.width === null ? [] : [`width: ${entry.width}`],
@@ -51236,7 +51793,7 @@ function renderNestedValue(context, member, value) {
51236
51793
  return renderDefaultValue(context, member, { value, classId: null });
51237
51794
  }
51238
51795
  function emitTextureTemplate(value) {
51239
- assertIdentifier(value.name, "texture template");
51796
+ assertProjectIdentifier(value.name, "texture template");
51240
51797
  const platformSettings = `new(
51241
51798
  ${namedArguments(
51242
51799
  [
@@ -51429,7 +51986,7 @@ function emitVector4(value) {
51429
51986
  return `new(x: ${value.x}, y: ${value.y}, z: ${value.z}, w: ${value.w})`;
51430
51987
  }
51431
51988
  function emitAudioTemplate(value) {
51432
- assertIdentifier(value.name, "audio template");
51989
+ assertProjectIdentifier(value.name, "audio template");
51433
51990
  const enumArguments = /* @__PURE__ */ new Set([
51434
51991
  "loadType",
51435
51992
  "compressionFormat",
@@ -51634,7 +52191,7 @@ function emitVariantFiles(context, variantInitializers) {
51634
52191
  function emitVariantFolder(context, className, folder) {
51635
52192
  for (const segment of folder.path.split("/")) {
51636
52193
  if (segment.length === 0) continue;
51637
- assertIdentifier(segment, "variant folder path segment");
52194
+ assertProjectIdentifier(segment, "variant folder path segment");
51638
52195
  }
51639
52196
  if (folder.binding === null) {
51640
52197
  return `${id(folder.id)}NeoVariantFolder<${className}> ${variantFolderSymbol(folder)} = new(${quote(folder.path)});`;
@@ -51654,7 +52211,7 @@ function emitVariantFolder(context, className, folder) {
51654
52211
  );`;
51655
52212
  }
51656
52213
  function emitVariant(context, className, variant, folder, variantInitializers) {
51657
- assertIdentifier(variant.name, "variant");
52214
+ assertProjectIdentifier(variant.name, "variant");
51658
52215
  const initializer = variantInitializers.get(variant.id);
51659
52216
  if (initializer === void 0) {
51660
52217
  throw new Error(
@@ -51709,13 +52266,20 @@ function assertUniqueEmittedPaths(files) {
51709
52266
  paths.set(key, file);
51710
52267
  }
51711
52268
  }
51712
- function assertIdentifier(value, kind) {
51713
- if (!isValidNeoIdentifier(value)) {
52269
+ function assertProjectIdentifier(value, kind) {
52270
+ if (!isValidNeoProjectIdentifier(value)) {
51714
52271
  throw new Error(
51715
52272
  `Persisted ${kind} name ${quote(value)} is not a valid Neo identifier; repair the server record before format-4 conversion.`
51716
52273
  );
51717
52274
  }
51718
52275
  }
52276
+ function assertMemberIdentifier(value, kind) {
52277
+ if (!isValidNeoProjectMemberIdentifier(value)) {
52278
+ throw new Error(
52279
+ `Persisted ${kind} name ${quote(value)} is not a valid Neo member identifier; repair the server record before format-4 conversion.`
52280
+ );
52281
+ }
52282
+ }
51719
52283
  function required(map, key, kind) {
51720
52284
  const value = map.get(key);
51721
52285
  if (!value) throw new Error(`Unknown ${kind} ${quote(key)}.`);
@@ -51829,7 +52393,7 @@ function assignDeterministicProjectFileSymbols(files, reservedSymbols = []) {
51829
52393
  const candidate = `${item.base}${collidesByStem ? item.extension : ""}`;
51830
52394
  let symbol = candidate;
51831
52395
  let suffix = 2;
51832
- while (used.has(symbol.toLowerCase()) || !isValidNeoIdentifier(symbol))
52396
+ while (used.has(symbol.toLowerCase()) || !isValidNeoProjectMemberIdentifier(symbol))
51833
52397
  symbol = `${candidate}_${suffix++}`;
51834
52398
  used.add(symbol.toLowerCase());
51835
52399
  result.set(item.stableId, symbol);
@@ -52450,7 +53014,7 @@ ${args.map(([name, value]) => ` ${name}: ${value},`).join("\n")}
52450
53014
  `;
52451
53015
  }
52452
53016
  function emitPriorityGroup(data, recordId, name) {
52453
- assertIdentifier2(name, "priority group");
53017
+ assertProjectIdentifier2(name, "priority group");
52454
53018
  const options = Array.isArray(data.options) ? data.options : [];
52455
53019
  const body = options.map((option, index) => {
52456
53020
  if (!isObjectRecord2(option) || typeof option.id !== "string" || typeof option.name !== "string") {
@@ -52458,7 +53022,7 @@ function emitPriorityGroup(data, recordId, name) {
52458
53022
  `Priority group ${recordId} option ${index} is malformed.`
52459
53023
  );
52460
53024
  }
52461
- assertIdentifier2(option.name, "priority option");
53025
+ assertMemberIdentifier2(option.name, "priority option");
52462
53026
  return ` @id(${quote2(option.id)})
52463
53027
  PriorityOption ${option.name} = new();`;
52464
53028
  });
@@ -52473,7 +53037,7 @@ ${body.join("\n\n")}
52473
53037
  `;
52474
53038
  }
52475
53039
  function emitDialogueGroup(data, recordId, name, priorityNames, dialogueNames, uiLogicResolver) {
52476
- assertIdentifier2(name, "dialogue group");
53040
+ assertProjectIdentifier2(name, "dialogue group");
52477
53041
  const kind = data.type === 1 ? "Lookup" : data.type === 2 ? "Folder" : "Standard";
52478
53042
  const args = [["kind", `.${kind}`]];
52479
53043
  const priority = reference(
@@ -52545,7 +53109,7 @@ function collectDialogueGroupFunctions(data, groupId, resolver) {
52545
53109
  let functionName = functionNameById.get(functionId);
52546
53110
  const code = typeof value.code === "string" ? value.code.trim() : value.type === 0 ? uiConditionSource(value.getter, resolver) : null;
52547
53111
  if (functionName === void 0) {
52548
- assertIdentifier2(requestedName, "dialogue group function");
53112
+ assertMemberIdentifier2(requestedName, "dialogue group function");
52549
53113
  functionName = uniqueIdentifier(requestedName, names);
52550
53114
  functions.set(functionId, { id: functionId, name: functionName, code });
52551
53115
  functionNameById.set(functionId, functionName);
@@ -53107,7 +53671,7 @@ function requiredName(data, record3) {
53107
53671
  if (typeof data.name !== "string") {
53108
53672
  throw new Error(`${record3.recordKind}:${record3.recordId} has no name.`);
53109
53673
  }
53110
- assertIdentifier2(data.name, record3.recordKind);
53674
+ assertProjectIdentifier2(data.name, record3.recordKind);
53111
53675
  return data.name;
53112
53676
  }
53113
53677
  function namesById(records2, kind) {
@@ -53199,7 +53763,7 @@ function normalizeSource(value) {
53199
53763
  return value.replace(/\s+/gu, " ").trim();
53200
53764
  }
53201
53765
  function isIdentifier(value) {
53202
- return /^[A-Za-z_][A-Za-z0-9_]*$/u.test(value);
53766
+ return isValidNeoProjectMemberIdentifier(value);
53203
53767
  }
53204
53768
  function reference(value, names, type) {
53205
53769
  if (value === void 0 || value === null) return null;
@@ -53250,13 +53814,20 @@ function enumCase2(value) {
53250
53814
  function lowerFirst2(value) {
53251
53815
  return `${value[0]?.toLowerCase() ?? ""}${value.slice(1)}`;
53252
53816
  }
53253
- function assertIdentifier2(value, kind) {
53254
- if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
53817
+ function assertProjectIdentifier2(value, kind) {
53818
+ if (!isValidNeoProjectIdentifier(value)) {
53255
53819
  throw new Error(
53256
53820
  `${kind} name ${JSON.stringify(value)} is not a valid Neo identifier.`
53257
53821
  );
53258
53822
  }
53259
53823
  }
53824
+ function assertMemberIdentifier2(value, kind) {
53825
+ if (!isValidNeoProjectMemberIdentifier(value)) {
53826
+ throw new Error(
53827
+ `${kind} name ${JSON.stringify(value)} is not a valid Neo member identifier.`
53828
+ );
53829
+ }
53830
+ }
53260
53831
  function uniqueIdentifier(requested, used) {
53261
53832
  let candidate = requested;
53262
53833
  let suffix = 2;
@@ -53967,6 +54538,7 @@ var init_interface_validation = __esm({
53967
54538
  "../src/models/interfaces/interface-validation.ts"() {
53968
54539
  "use strict";
53969
54540
  init_member_kinds();
54541
+ init_schema_identifiers();
53970
54542
  init_interface_conformance();
53971
54543
  init_interface_graph();
53972
54544
  }
@@ -56024,6 +56596,17 @@ function expressionReadsRuntimeIdentifier(expression, runtimeIdentifiers) {
56024
56596
  case "binary":
56025
56597
  case "coalesce":
56026
56598
  return expressionReadsRuntimeIdentifier(expression.left, runtimeIdentifiers) || expressionReadsRuntimeIdentifier(expression.right, runtimeIdentifiers);
56599
+ case "conditional":
56600
+ return expressionReadsRuntimeIdentifier(
56601
+ expression.condition,
56602
+ runtimeIdentifiers
56603
+ ) || expressionReadsRuntimeIdentifier(
56604
+ expression.whenTrue,
56605
+ runtimeIdentifiers
56606
+ ) || expressionReadsRuntimeIdentifier(
56607
+ expression.whenFalse,
56608
+ runtimeIdentifiers
56609
+ );
56027
56610
  case "unary":
56028
56611
  case "force":
56029
56612
  case "is":
@@ -56055,6 +56638,7 @@ function isEvaluatedOnlyExpression(expression) {
56055
56638
  return isEvaluatedOnlyExpression(expression.expression);
56056
56639
  case "binary":
56057
56640
  case "coalesce":
56641
+ case "conditional":
56058
56642
  case "index":
56059
56643
  case "is":
56060
56644
  case "force":
@@ -66995,6 +67579,9 @@ function evalPointer(pointer, scope, ctx) {
66995
67579
  (arg) => evalPointer(arg, scope, ctx)
66996
67580
  );
66997
67581
  const member = pointer.receiver.kind === "static" ? evalMemberById(ctx.vm, pointer.receiver.memberId) : resolveEffectiveCallableMember(pointer, innerThis, ctx);
67582
+ if (member !== null && pointer.missingMemberFallback === "valueEquality") {
67583
+ assertValueEqualitySignature(member, innerThis, ctx);
67584
+ }
66998
67585
  const args = fillCallableCallSiteArguments(suppliedArgs, member, ctx);
66999
67586
  const interceptedMemberId = member?.id ?? pointer.memberId ?? pointer.memberKey ?? pointer.callSiteId;
67000
67587
  consumeBudget(ctx, "workUnits", 1, "work unit");
@@ -67008,6 +67595,9 @@ function evalPointer(pointer, scope, ctx) {
67008
67595
  });
67009
67596
  if (intercepted?.handled === true) return intercepted.value;
67010
67597
  if (member === null) {
67598
+ if (pointer.missingMemberFallback === "valueEquality") {
67599
+ return jsEqual(innerThis, suppliedArgs[0]);
67600
+ }
67011
67601
  throw new NSGetterRuntimeError(
67012
67602
  `Function call '${pointer.memberKey ?? pointer.memberId ?? pointer.callSiteId}' could not be resolved on the receiver's runtime class.`
67013
67603
  );
@@ -67121,6 +67711,24 @@ function evalPointer(pointer, scope, ctx) {
67121
67711
  if (left !== null && left !== void 0) return left;
67122
67712
  return evalPointer(pointer.right, scope, ctx);
67123
67713
  }
67714
+ case "conditional" /* conditional */: {
67715
+ const condition = evalPointer(pointer.condition, scope, ctx);
67716
+ return evalPointer(
67717
+ jsTruthy(condition) ? pointer.whenTrue : pointer.whenFalse,
67718
+ scope,
67719
+ ctx
67720
+ );
67721
+ }
67722
+ case "delegateClosure" /* delegateClosure */:
67723
+ return {
67724
+ ...pointer.code === void 0 ? {} : { code: pointer.code },
67725
+ action: pointer.action,
67726
+ captures: pointer.captures.map(
67727
+ (capture) => evalPointer(capture, scope, ctx)
67728
+ ),
67729
+ ...ctx.thisValue === null || ctx.thisValue === void 0 ? {} : { [DELEGATE_LEXICAL_THIS]: ctx.thisValue },
67730
+ [DELEGATE_LEXICAL_ROOT]: ctx.rootValue
67731
+ };
67124
67732
  case "toBool" /* toBool */: {
67125
67733
  const v = evalPointer(pointer.pointer, scope, ctx);
67126
67734
  return jsTruthy(v);
@@ -67149,6 +67757,34 @@ function resolveEffectiveCallableMember(pointer, receiver, ctx) {
67149
67757
  const runtimeMember = resolveRuntimeSchemaMember(receiver, schemaKey, ctx);
67150
67758
  return runtimeMember ?? staticMember;
67151
67759
  }
67760
+ function assertValueEqualitySignature(member, receiver, ctx) {
67761
+ if (member.kind !== 13 /* Function */ && member.kind !== 23 /* NSFunction */) {
67762
+ throw new NSGetterRuntimeError(
67763
+ `Generic Equals resolved to non-callable member '${member.name}'.`
67764
+ );
67765
+ }
67766
+ const signature = resolveCallableSignature(member.id, member.kind, ctx);
67767
+ if (signature === null) {
67768
+ throw new NSGetterRuntimeError(
67769
+ `Generic Equals member '${member.name}' has no resolvable signature.`
67770
+ );
67771
+ }
67772
+ const runtimeSignature = substituteCallableSignatureForReceiver(
67773
+ signature,
67774
+ receiver,
67775
+ ctx
67776
+ );
67777
+ if (runtimeSignature.argumentTypes.length !== 1) {
67778
+ throw new NSGetterRuntimeError(
67779
+ `Generic Equals member '${member.name}' must take exactly one argument; found ${runtimeSignature.argumentTypes.length}.`
67780
+ );
67781
+ }
67782
+ if (runtimeSignature.returnTypeInfo.type !== 1 /* Bool */) {
67783
+ throw new NSGetterRuntimeError(
67784
+ `Generic Equals member '${member.name}' must return bool.`
67785
+ );
67786
+ }
67787
+ }
67152
67788
  function invokeDelegateValue(value, args, ctx, callSiteId, ownerReceiver) {
67153
67789
  if (isNSDelegateClosureValueDraft(value)) {
67154
67790
  throw new NSGetterRuntimeError(
@@ -67158,6 +67794,7 @@ function invokeDelegateValue(value, args, ctx, callSiteId, ownerReceiver) {
67158
67794
  if (isNSDelegateClosureValue(value)) {
67159
67795
  const closure = value;
67160
67796
  const thisValue = delegateClosureLexicalThis(closure, ctx);
67797
+ const captures = closure.captures ?? [];
67161
67798
  return executeCompiledFunction(
67162
67799
  value.action,
67163
67800
  {
@@ -67165,7 +67802,7 @@ function invokeDelegateValue(value, args, ctx, callSiteId, ownerReceiver) {
67165
67802
  thisValue,
67166
67803
  rootValue: closure[DELEGATE_LEXICAL_ROOT] ?? ctx.rootValue
67167
67804
  },
67168
- args,
67805
+ [...args, ...captures],
67169
67806
  value.action.typeInfo.type === 0 /* Null */
67170
67807
  );
67171
67808
  }
@@ -72799,22 +73436,22 @@ var init_init_backed_value_materialization = __esm({
72799
73436
  function hasRejectedConstructorKey(value) {
72800
73437
  return REJECTED_CONSTRUCTOR_KEYS.some((key) => value[key] !== void 0);
72801
73438
  }
72802
- function isNamedBaseClauseEntry(value) {
73439
+ function isNamedBaseClauseEntry(value, nameIsValid) {
72803
73440
  if (typeof value !== "object" || value === null) return false;
72804
73441
  if (Array.isArray(value)) return false;
72805
73442
  const candidate = value;
72806
73443
  if (!Object.keys(candidate).every((key) => key === "name" || key === "code")) {
72807
73444
  return false;
72808
73445
  }
72809
- if (!isValidCallableIdentifier(candidate.name)) return false;
73446
+ if (!nameIsValid(candidate.name)) return false;
72810
73447
  if (typeof candidate.code !== "string") return false;
72811
73448
  return candidate.code.length > 0;
72812
73449
  }
72813
73450
  function isNeoConstructorBaseArgument(value) {
72814
- return isNamedBaseClauseEntry(value);
73451
+ return isNamedBaseClauseEntry(value, isValidCallableArgumentIdentifier);
72815
73452
  }
72816
73453
  function isNeoConstructorBaseInitializerField(value) {
72817
- return isNamedBaseClauseEntry(value);
73454
+ return isNamedBaseClauseEntry(value, isValidSchemaMemberIdentifier);
72818
73455
  }
72819
73456
  function isNeoClassConstructorBase(value) {
72820
73457
  if (typeof value !== "object" || value === null) return false;
@@ -72830,7 +73467,7 @@ function isNeoClassConstructorBase(value) {
72830
73467
  const argumentTypes = [];
72831
73468
  for (const argument2 of v.argumentTypes) {
72832
73469
  if (!isNSFunctionArgumentTypeInfo(argument2)) return false;
72833
- if (!isValidCallableIdentifier(argument2.name)) return false;
73470
+ if (!isValidCallableArgumentIdentifier(argument2.name)) return false;
72834
73471
  if (parameterNames.has(argument2.name)) return false;
72835
73472
  parameterNames.add(argument2.name);
72836
73473
  argumentTypes.push(argument2);
@@ -72929,6 +73566,7 @@ var init_constructors = __esm({
72929
73566
  init_core();
72930
73567
  init_docs_text2();
72931
73568
  init_member_kinds();
73569
+ init_schema_identifiers();
72932
73570
  init_neoscript();
72933
73571
  REJECTED_CONSTRUCTOR_KEYS = [
72934
73572
  "bodyMode",
@@ -83113,8 +83751,20 @@ function stableValue(value) {
83113
83751
  function stableTypeInfo(value) {
83114
83752
  return JSON.stringify(stableValue(value));
83115
83753
  }
83116
- function isOpaqueCallableIdentifier(value) {
83117
- return typeof value === "string" && OPAQUE_CALLABLE_IDENTIFIER_PATTERN.test(value) && !value.startsWith("__") && !OPAQUE_CALLABLE_RESERVED_NAMES.has(value);
83754
+ function isOpaqueGeneratedIdentifier(value, neoPredicate) {
83755
+ return typeof value === "string" && neoPredicate(value) && isGeneratedCSharpIdentifier(value) && !isGeneratedCSharpReservedKeyword(value);
83756
+ }
83757
+ function isOpaqueSchemaMemberIdentifier(value) {
83758
+ return isOpaqueGeneratedIdentifier(value, isValidNeoProjectMemberIdentifier);
83759
+ }
83760
+ function isOpaqueCallableMemberIdentifier(value) {
83761
+ return isOpaqueSchemaMemberIdentifier(value) && !value.startsWith("__");
83762
+ }
83763
+ function isOpaqueCallableArgumentIdentifier(value) {
83764
+ return isOpaqueGeneratedIdentifier(value, isValidNeoProjectBindingIdentifier) && !value.startsWith("__");
83765
+ }
83766
+ function isOpaqueNSFunctionArgumentIdentifier(value) {
83767
+ return isOpaqueCallableArgumentIdentifier(value) && value !== "value";
83118
83768
  }
83119
83769
  function isOpaqueNSTypeInfo(value, ancestors = /* @__PURE__ */ new Set()) {
83120
83770
  if (!isRecord7(value) || typeof value.required !== "boolean") return false;
@@ -83208,11 +83858,11 @@ function isOpaqueNSFunctionReturnTypeInfo(value) {
83208
83858
  return isOpaqueNSTypeInfo(value);
83209
83859
  }
83210
83860
  function isOpaqueNSFunctionArgumentTypeInfo(value) {
83211
- return isOpaqueNSTypeInfo(value) && isOpaqueCallableIdentifier(value.name) && !opaqueTypeInfoContainsUnknown(value) && hasValidOpaqueParameterDefault(value);
83861
+ return isOpaqueNSTypeInfo(value) && isOpaqueNSFunctionArgumentIdentifier(value.name) && !opaqueTypeInfoContainsUnknown(value) && hasValidOpaqueParameterDefault(value);
83212
83862
  }
83213
83863
  function isOpaqueConstructorArgumentTypeInfo(value) {
83214
83864
  if (!isRecord7(value)) return false;
83215
- return isOpaqueNSTypeInfo(value) && (value.name === "value" || isOpaqueCallableIdentifier(value.name)) && !opaqueTypeInfoContainsUnknown(value) && hasValidOpaqueParameterDefault(value);
83865
+ return isOpaqueNSTypeInfo(value) && isOpaqueCallableArgumentIdentifier(value.name) && !opaqueTypeInfoContainsUnknown(value) && hasValidOpaqueParameterDefault(value);
83216
83866
  }
83217
83867
  function hasValidOpaqueParameterDefault(value) {
83218
83868
  const wrapper = value.defaultValue;
@@ -84665,7 +85315,8 @@ function assertOpaqueBaseClauseListValid(declaredConstructor, spec) {
84665
85315
  `Constructor "${declaredConstructor.id}" has a ${spec.entryLabel} that is not an object.`
84666
85316
  );
84667
85317
  }
84668
- if (!isOpaqueCallableIdentifier(entry.name)) {
85318
+ const nameIsValid = spec.nameKind === "member" ? isOpaqueSchemaMemberIdentifier : isOpaqueCallableArgumentIdentifier;
85319
+ if (!nameIsValid(entry.name)) {
84669
85320
  throw new Error(
84670
85321
  `Constructor "${declaredConstructor.id}" has a ${spec.entryLabel} with an invalid name.`
84671
85322
  );
@@ -84966,7 +85617,7 @@ function assertOpaqueMemberDefaultValueValid(member) {
84966
85617
  }
84967
85618
  function assertOpaqueNSFunctionValid(member, membersById) {
84968
85619
  if (member.kind !== 23) return;
84969
- if (!isOpaqueCallableIdentifier(member.name)) {
85620
+ if (!isOpaqueCallableMemberIdentifier(member.name)) {
84970
85621
  throw new Error(`NSFunction "${member.id}" name is invalid.`);
84971
85622
  }
84972
85623
  if (member.storage !== void 0 && member.storage !== null) {
@@ -85102,34 +85753,14 @@ function assertOpaqueNSFunctionValid(member, membersById) {
85102
85753
  deferred: member.deferred
85103
85754
  });
85104
85755
  }
85105
- var NEO_OBJECT_WORLD_KIND, READ_ONLY_SYNTHETIC_VALUE_ID_PREFIX2, OPAQUE_CALLABLE_IDENTIFIER_PATTERN, OPAQUE_CALLABLE_RESERVED_NAMES, REJECTED_OPAQUE_CONSTRUCTOR_KEYS, OPAQUE_INITIALIZER_KEYS, OPAQUE_BASE_ARGUMENTS_SPEC, OPAQUE_BASE_INITIALIZER_FIELDS_SPEC;
85756
+ var NEO_OBJECT_WORLD_KIND, READ_ONLY_SYNTHETIC_VALUE_ID_PREFIX2, REJECTED_OPAQUE_CONSTRUCTOR_KEYS, OPAQUE_INITIALIZER_KEYS, OPAQUE_BASE_ARGUMENTS_SPEC, OPAQUE_BASE_INITIALIZER_FIELDS_SPEC;
85106
85757
  var init_projectInterfaceValidation = __esm({
85107
85758
  "../convex/projectInterfaceValidation.ts"() {
85108
85759
  "use strict";
85109
85760
  init_projectVariantValidation();
85761
+ init_src();
85110
85762
  NEO_OBJECT_WORLD_KIND = "object";
85111
85763
  READ_ONLY_SYNTHETIC_VALUE_ID_PREFIX2 = "__neo_readonly_default:";
85112
- OPAQUE_CALLABLE_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
85113
- OPAQUE_CALLABLE_RESERVED_NAMES = /* @__PURE__ */ new Set([
85114
- "this",
85115
- "root",
85116
- "context",
85117
- "value",
85118
- "true",
85119
- "false",
85120
- "null",
85121
- "void",
85122
- "if",
85123
- "else",
85124
- "return",
85125
- "throw",
85126
- "var",
85127
- "int",
85128
- "float",
85129
- "decimal",
85130
- "string",
85131
- "bool"
85132
- ]);
85133
85764
  REJECTED_OPAQUE_CONSTRUCTOR_KEYS = [
85134
85765
  "bodyMode",
85135
85766
  "uiAction",
@@ -85140,6 +85771,7 @@ var init_projectInterfaceValidation = __esm({
85140
85771
  OPAQUE_BASE_ARGUMENTS_SPEC = {
85141
85772
  authoredKey: "baseArguments",
85142
85773
  compiledKey: "compiledBaseArguments",
85774
+ nameKind: "parameter",
85143
85775
  entryLabel: "base argument",
85144
85776
  compiledLabel: "compiled base arguments",
85145
85777
  clauseLabel: "a base call"
@@ -85147,6 +85779,7 @@ var init_projectInterfaceValidation = __esm({
85147
85779
  OPAQUE_BASE_INITIALIZER_FIELDS_SPEC = {
85148
85780
  authoredKey: "baseInitializerFields",
85149
85781
  compiledKey: "compiledBaseInitializerFields",
85782
+ nameKind: "member",
85150
85783
  entryLabel: "base initializer field",
85151
85784
  compiledLabel: "compiled base initializer fields",
85152
85785
  clauseLabel: "a base initializer block"
@@ -85158,34 +85791,37 @@ var init_projectInterfaceValidation = __esm({
85158
85791
  function isRecord8(value) {
85159
85792
  return typeof value === "object" && value !== null && !Array.isArray(value);
85160
85793
  }
85161
- function assertIdentifier3(value, label) {
85162
- if (isValidSchemaAuthoredIdentifier(value)) return;
85794
+ function assertIdentifier(value, label, predicate) {
85795
+ if (predicate(value)) return;
85163
85796
  throw new Error(
85164
85797
  `${label} must be a valid Neo/codegen identifier; use letters, digits, and underscores, begin with a letter or underscore, and avoid reserved language keywords.`
85165
85798
  );
85166
85799
  }
85167
- function assertArgumentIdentifiers(value, ownerLabel) {
85800
+ function assertArgumentIdentifiers(value, ownerLabel, predicate) {
85168
85801
  if (!Array.isArray(value)) return;
85169
85802
  for (let index = 0; index < value.length; index += 1) {
85170
85803
  const argument2 = value[index];
85171
85804
  if (!isRecord8(argument2)) continue;
85172
- assertIdentifier3(
85805
+ assertIdentifier(
85173
85806
  argument2.name,
85174
- `${ownerLabel} parameter ${index + 1} name ${JSON.stringify(argument2.name)}`
85807
+ `${ownerLabel} parameter ${index + 1} name ${JSON.stringify(argument2.name)}`,
85808
+ predicate
85175
85809
  );
85176
85810
  }
85177
85811
  }
85178
85812
  function assertClassIdentifiers(recordId, value) {
85179
85813
  if (!isRecord8(value)) return;
85180
- assertIdentifier3(
85814
+ assertIdentifier(
85181
85815
  value.name,
85182
- `Class "${recordId}" name ${JSON.stringify(value.name)}`
85816
+ `Class "${recordId}" name ${JSON.stringify(value.name)}`,
85817
+ isValidSchemaAuthoredIdentifier
85183
85818
  );
85184
85819
  if (isRecord8(value.schema)) {
85185
85820
  for (const schemaKey of Object.keys(value.schema)) {
85186
- assertIdentifier3(
85821
+ assertIdentifier(
85187
85822
  schemaKey,
85188
- `Class "${recordId}" schema key ${JSON.stringify(schemaKey)}`
85823
+ `Class "${recordId}" schema key ${JSON.stringify(schemaKey)}`,
85824
+ isValidSchemaMemberIdentifier
85189
85825
  );
85190
85826
  }
85191
85827
  }
@@ -85193,17 +85829,19 @@ function assertClassIdentifiers(recordId, value) {
85193
85829
  for (let index = 0; index < value.genericParams.length; index += 1) {
85194
85830
  const parameter4 = value.genericParams[index];
85195
85831
  if (!isRecord8(parameter4)) continue;
85196
- assertIdentifier3(
85832
+ assertIdentifier(
85197
85833
  parameter4.name,
85198
- `Class "${recordId}" generic parameter ${index + 1} name ${JSON.stringify(parameter4.name)}`
85834
+ `Class "${recordId}" generic parameter ${index + 1} name ${JSON.stringify(parameter4.name)}`,
85835
+ isValidSchemaBindingIdentifier
85199
85836
  );
85200
85837
  }
85201
85838
  }
85202
85839
  function assertEnumIdentifiers(recordId, value) {
85203
85840
  if (!isRecord8(value)) return;
85204
- assertIdentifier3(
85841
+ assertIdentifier(
85205
85842
  value.name,
85206
- `Enum "${recordId}" name ${JSON.stringify(value.name)}`
85843
+ `Enum "${recordId}" name ${JSON.stringify(value.name)}`,
85844
+ isValidSchemaAuthoredIdentifier
85207
85845
  );
85208
85846
  if (!isRecord8(value.options)) return;
85209
85847
  const optionIdsByFoldedName = /* @__PURE__ */ new Map();
@@ -85219,9 +85857,10 @@ function assertEnumIdentifiers(recordId, value) {
85219
85857
  `Enum "${recordId}" option "${optionId}" must embed the same stable id.`
85220
85858
  );
85221
85859
  }
85222
- assertIdentifier3(
85860
+ assertIdentifier(
85223
85861
  option.name,
85224
- `Enum "${recordId}" option "${optionId}" name ${JSON.stringify(option.name)}`
85862
+ `Enum "${recordId}" option "${optionId}" name ${JSON.stringify(option.name)}`,
85863
+ isValidSchemaMemberIdentifier
85225
85864
  );
85226
85865
  const foldedName = option.name.toLowerCase();
85227
85866
  const collidingOptionId = optionIdsByFoldedName.get(foldedName);
@@ -85235,20 +85874,23 @@ function assertEnumIdentifiers(recordId, value) {
85235
85874
  }
85236
85875
  function assertInterfaceIdentifiers(recordId, value) {
85237
85876
  if (!isRecord8(value)) return;
85238
- assertIdentifier3(
85877
+ assertIdentifier(
85239
85878
  value.name,
85240
- `Interface "${recordId}" name ${JSON.stringify(value.name)}`
85879
+ `Interface "${recordId}" name ${JSON.stringify(value.name)}`,
85880
+ isValidSchemaAuthoredIdentifier
85241
85881
  );
85242
85882
  if (!isRecord8(value.members)) return;
85243
85883
  for (const [memberKey, member] of Object.entries(value.members)) {
85244
- assertIdentifier3(
85884
+ assertIdentifier(
85245
85885
  memberKey,
85246
- `Interface "${recordId}" member name ${JSON.stringify(memberKey)}`
85886
+ `Interface "${recordId}" member name ${JSON.stringify(memberKey)}`,
85887
+ isValidSchemaMemberIdentifier
85247
85888
  );
85248
85889
  if (!isRecord8(member) || member.kind !== "function") continue;
85249
85890
  assertArgumentIdentifiers(
85250
85891
  member.argumentTypes,
85251
- `Interface "${recordId}" function "${memberKey}"`
85892
+ `Interface "${recordId}" function "${memberKey}"`,
85893
+ isValidSchemaNSFunctionBindingIdentifier
85252
85894
  );
85253
85895
  }
85254
85896
  }
@@ -85260,15 +85902,17 @@ function isCallableOrPropertyMemberKind(value) {
85260
85902
  function assertMemberIdentifiers(recordId, value, directlyAuthoredMemberIds) {
85261
85903
  if (!isRecord8(value)) return;
85262
85904
  if (directlyAuthoredMemberIds.has(recordId) || isCallableOrPropertyMemberKind(value)) {
85263
- assertIdentifier3(
85905
+ assertIdentifier(
85264
85906
  value.name,
85265
- `Member "${recordId}" name ${JSON.stringify(value.name)}`
85907
+ `Member "${recordId}" name ${JSON.stringify(value.name)}`,
85908
+ isValidSchemaMemberIdentifier
85266
85909
  );
85267
85910
  }
85268
85911
  if (value.kind !== 13 && value.kind !== 23) return;
85269
85912
  assertArgumentIdentifiers(
85270
85913
  value.argumentTypes,
85271
- `Function member "${recordId}"`
85914
+ `Function member "${recordId}"`,
85915
+ value.kind === 23 ? isValidSchemaNSFunctionBindingIdentifier : isValidSchemaBindingIdentifier
85272
85916
  );
85273
85917
  }
85274
85918
  function assertSchemaIdentifierWriteChangesValid(changes, directlyAuthoredMemberIds) {
@@ -112267,7 +112911,7 @@ var init_registry2 = __esm({
112267
112911
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
112268
112912
  formatVersion: 3,
112269
112913
  contractVersion: "3.13",
112270
- cliVersion: "0.32.3",
112914
+ cliVersion: "0.33.0",
112271
112915
  projectFileUploadBatchSize: 32,
112272
112916
  documentRecords: {
112273
112917
  member: {
@@ -118862,7 +119506,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
118862
119506
  async function main() {
118863
119507
  const args = parseArgs(process.argv.slice(2));
118864
119508
  if (args.command === "--version") {
118865
- console.log("0.32.3");
119509
+ console.log("0.33.0");
118866
119510
  return;
118867
119511
  }
118868
119512
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {