@neocompose/cli 0.6.7 → 0.7.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
@@ -828,6 +828,7 @@ var init_document_contracts = __esm({
828
828
  "locked",
829
829
  "required",
830
830
  "isStatic",
831
+ "isReadOnly",
831
832
  "isVirtual",
832
833
  "isAbstract",
833
834
  "accessModifierKind",
@@ -870,6 +871,7 @@ var init_document_contracts = __esm({
870
871
  isAbstract: "missingIsFalseOnFullMember",
871
872
  locked: "missingIsFalseOnFullMember",
872
873
  required: "missingIsFalseOnFullMember",
874
+ isReadOnly: "missingIsFalseOnFullMember",
873
875
  defaultValue: "nullIsAbsent",
874
876
  extendsMemberId: "nullIsAbsent",
875
877
  system: "nullIsAbsent",
@@ -1452,6 +1454,7 @@ var init_language_spec = __esm({
1452
1454
  "private",
1453
1455
  "protected",
1454
1456
  "public",
1457
+ "readonly",
1455
1458
  "return",
1456
1459
  "sealed",
1457
1460
  "static",
@@ -6023,9 +6026,11 @@ var init_strict_parser = __esm({
6023
6026
  });
6024
6027
 
6025
6028
  // ../packages/neoscript-language/src/strict-ir.ts
6029
+ var NEOSCRIPT_COMPILER_REVISION;
6026
6030
  var init_strict_ir = __esm({
6027
6031
  "../packages/neoscript-language/src/strict-ir.ts"() {
6028
6032
  "use strict";
6033
+ NEOSCRIPT_COMPILER_REVISION = 2;
6029
6034
  }
6030
6035
  });
6031
6036
 
@@ -6799,6 +6804,7 @@ var init_strict_resolver = __esm({
6799
6804
  "use strict";
6800
6805
  init_project();
6801
6806
  init_strict_compile_error();
6807
+ init_strict_ir();
6802
6808
  Scope = class {
6803
6809
  constructor(parent) {
6804
6810
  this.parent = parent;
@@ -6976,6 +6982,7 @@ var init_strict_resolver = __esm({
6976
6982
  if (this.valueVariable) parameters.push(this.valueVariable);
6977
6983
  parameters.push(...this.argumentVariables.map((entry) => entry.variable));
6978
6984
  return {
6985
+ compilerRevision: NEOSCRIPT_COMPILER_REVISION,
6979
6986
  parameters,
6980
6987
  instructions,
6981
6988
  typeInfo: toWireType(returnType, this.project)
@@ -7237,7 +7244,7 @@ var init_strict_resolver = __esm({
7237
7244
  }
7238
7245
  if (!writability || writability === "readOnly" /* ReadOnly */ || writability === "immutable" /* Immutable */) {
7239
7246
  throw new CompileError(
7240
- writability === "immutable" /* Immutable */ ? "Cannot assign because the target's effective storage is immutable." : `Cannot assign to a read-only ${this.describe(target.type)} value.`,
7247
+ target.symbol?.readonlyDeclaration === true ? `Member '${target.symbol.name}' is readonly and can only be changed through its class default.` : writability === "immutable" /* Immutable */ ? "Cannot assign because the target's effective storage is immutable." : `Cannot assign to a read-only ${this.describe(target.type)} value.`,
7241
7248
  statement.pos
7242
7249
  );
7243
7250
  }
@@ -8054,7 +8061,8 @@ var init_strict_resolver = __esm({
8054
8061
  receiver,
8055
8062
  member.schemaKey ?? member.name,
8056
8063
  memberType2,
8057
- optional
8064
+ optional,
8065
+ member.id
8058
8066
  ),
8059
8067
  symbol: member,
8060
8068
  ...writability ? { writability } : {},
@@ -8091,10 +8099,11 @@ var init_strict_resolver = __esm({
8091
8099
  }
8092
8100
  return targetWritability;
8093
8101
  }
8094
- keyOf(receiver, key, type, optional) {
8102
+ keyOf(receiver, key, type, optional, memberId) {
8095
8103
  return {
8096
8104
  pointer: {
8097
8105
  type: "keyOf" /* KeyOf */,
8106
+ ...memberId ? { memberId } : {},
8098
8107
  keyOf: { pointer: receiver.pointer, key: stringPointer(key) },
8099
8108
  ...optional ? { optional: true } : {}
8100
8109
  },
@@ -8846,6 +8855,7 @@ var init_strict_resolver = __esm({
8846
8855
  );
8847
8856
  }
8848
8857
  return {
8858
+ compilerRevision: NEOSCRIPT_COMPILER_REVISION,
8849
8859
  parameters,
8850
8860
  instructions,
8851
8861
  typeInfo: toWireType(returnType, this.project)
@@ -11115,6 +11125,7 @@ var init_project_source_parser = __esm({
11115
11125
  "private",
11116
11126
  "protected",
11117
11127
  "public",
11128
+ "readonly",
11118
11129
  "sealed",
11119
11130
  "static",
11120
11131
  "virtual"
@@ -11801,7 +11812,7 @@ var init_project_schema_contract_generated = __esm({
11801
11812
  "../packages/neoscript-language/src/project-schema-contract.generated.ts"() {
11802
11813
  "use strict";
11803
11814
  PROJECT_SCHEMA_MANIFEST_FORMAT_VERSION = 3;
11804
- PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION = "3.2";
11815
+ PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION = "3.3";
11805
11816
  NEO_PROJECT_SOURCE_RECORD_CONTRACT = {
11806
11817
  "recordFields": {
11807
11818
  "member": [
@@ -11812,6 +11823,7 @@ var init_project_schema_contract_generated = __esm({
11812
11823
  "locked",
11813
11824
  "required",
11814
11825
  "isStatic",
11826
+ "isReadOnly",
11815
11827
  "isVirtual",
11816
11828
  "isAbstract",
11817
11829
  "accessModifierKind",
@@ -15782,6 +15794,7 @@ function buildProjectGraph(documents) {
15782
15794
  (memberId) => {
15783
15795
  const member = membersBySymbolId.get(memberId);
15784
15796
  if (!member || member.kind !== "field") return null;
15797
+ if (member.modifiers.includes("readonly")) return null;
15785
15798
  return {
15786
15799
  required: member.initializer === void 0,
15787
15800
  defaultValue: member.initializer?.text
@@ -15839,6 +15852,7 @@ function sourceMemberSymbol(member, owner, typeIds, source) {
15839
15852
  );
15840
15853
  const type = sourceTypeRef(member.type, owner, typeIds);
15841
15854
  const staticMember = member.modifiers.includes("static");
15855
+ const readonlyDeclaration = member.modifiers.includes("readonly");
15842
15856
  const common = {
15843
15857
  id: id2,
15844
15858
  name: member.name,
@@ -15851,7 +15865,8 @@ function sourceMemberSymbol(member, owner, typeIds, source) {
15851
15865
  owner.declaration.kind
15852
15866
  ),
15853
15867
  location: location(owner.uri, member.range),
15854
- selectionLocation: location(owner.uri, member.nameRange)
15868
+ selectionLocation: location(owner.uri, member.nameRange),
15869
+ ...readonlyDeclaration ? { readonlyDeclaration: true } : {}
15855
15870
  };
15856
15871
  if (member.kind === "function") {
15857
15872
  return {
@@ -15882,8 +15897,8 @@ function sourceMemberSymbol(member, owner, typeIds, source) {
15882
15897
  return {
15883
15898
  ...common,
15884
15899
  kind: "property",
15885
- writable: writability !== "immutable" && writability !== "readOnly",
15886
- writability
15900
+ writable: !readonlyDeclaration && writability !== "immutable" && writability !== "readOnly",
15901
+ writability: readonlyDeclaration ? "readOnly" : writability
15887
15902
  };
15888
15903
  }
15889
15904
  function substituteInheritedSourceMember(member, baseInfo, resolvedBaseType) {
@@ -16243,6 +16258,7 @@ function createEnvironment2(documents) {
16243
16258
  if (declaration.kind === "class") {
16244
16259
  const ref = {
16245
16260
  uri,
16261
+ sourceKind: document.kind,
16246
16262
  declaration,
16247
16263
  location: { uri, range: declaration.nameRange }
16248
16264
  };
@@ -16256,6 +16272,7 @@ function createEnvironment2(documents) {
16256
16272
  } else {
16257
16273
  const ref = {
16258
16274
  uri,
16275
+ sourceKind: document.kind,
16259
16276
  declaration,
16260
16277
  location: { uri, range: declaration.nameRange }
16261
16278
  };
@@ -16740,6 +16757,16 @@ function validateMembers(environment, diagnostics) {
16740
16757
  );
16741
16758
  }
16742
16759
  for (const modifier of member.modifiers) {
16760
+ if (modifier === "readonly") {
16761
+ diagnose(
16762
+ diagnostics,
16763
+ ref.uri,
16764
+ member.nameRange,
16765
+ "readonly-interface-member",
16766
+ `Interface member '${member.name}' cannot use 'readonly'; readonly is valid only on a class field.`
16767
+ );
16768
+ continue;
16769
+ }
16743
16770
  if (modifier === "async" && member.kind === "function") continue;
16744
16771
  if (isNeoSourceAccessModifier(modifier)) continue;
16745
16772
  diagnose(
@@ -16754,7 +16781,7 @@ function validateMembers(environment, diagnostics) {
16754
16781
  validateInterfaceMemberConflicts(ref, environment, diagnostics);
16755
16782
  }
16756
16783
  for (const ref of environment.classes.values()) {
16757
- validateClassMemberModifiers(ref, diagnostics);
16784
+ validateClassMemberModifiers(ref, environment, diagnostics);
16758
16785
  validateClassOverrides(ref, environment, diagnostics);
16759
16786
  if (ref.declaration.modifiers.includes("abstract")) {
16760
16787
  validateAbstractInterfaceMembers(ref, environment, diagnostics);
@@ -16863,10 +16890,67 @@ function validateAbstractInterfaceMembers(ref, environment, diagnostics) {
16863
16890
  );
16864
16891
  }
16865
16892
  }
16866
- function validateClassMemberModifiers(ref, diagnostics) {
16893
+ function validateClassMemberModifiers(ref, environment, diagnostics) {
16867
16894
  const classIsAbstract = ref.declaration.modifiers.includes("abstract");
16868
16895
  for (const member of ref.declaration.members) {
16869
16896
  const modifiers = new Set(member.modifiers);
16897
+ if (modifiers.has("readonly")) {
16898
+ if (ref.sourceKind === "flow") {
16899
+ diagnose(
16900
+ diagnostics,
16901
+ ref.uri,
16902
+ member.nameRange,
16903
+ "readonly-neoflow-binding",
16904
+ `NeoFlow binding '${member.name}' cannot use 'readonly'; readonly is valid only on a class field in a .neo definition.`
16905
+ );
16906
+ } else if (member.kind !== "field") {
16907
+ diagnose(
16908
+ diagnostics,
16909
+ ref.uri,
16910
+ member.nameRange,
16911
+ "readonly-non-field-member",
16912
+ `Member '${member.name}' cannot use 'readonly'; readonly is valid only on a class field.`
16913
+ );
16914
+ } else {
16915
+ if (modifiers.has("static")) {
16916
+ diagnose(
16917
+ diagnostics,
16918
+ ref.uri,
16919
+ member.nameRange,
16920
+ "static-readonly-member",
16921
+ `Read-only field '${member.name}' cannot be static.`
16922
+ );
16923
+ }
16924
+ if (modifiers.has("abstract")) {
16925
+ diagnose(
16926
+ diagnostics,
16927
+ ref.uri,
16928
+ member.nameRange,
16929
+ "abstract-readonly-member",
16930
+ `Read-only field '${member.name}' cannot be abstract.`
16931
+ );
16932
+ }
16933
+ if (member.initializer === void 0) {
16934
+ diagnose(
16935
+ diagnostics,
16936
+ ref.uri,
16937
+ member.nameRange,
16938
+ "readonly-member-initializer",
16939
+ `Read-only field '${member.name}' requires an explicit initializer.`
16940
+ );
16941
+ }
16942
+ const storage = resolvedSourceMemberStorage(ref, member, environment);
16943
+ if (storage !== "immutable") {
16944
+ diagnose(
16945
+ diagnostics,
16946
+ ref.uri,
16947
+ member.nameRange,
16948
+ "readonly-member-storage",
16949
+ `Read-only field '${member.name}' requires resolved @storage(allowed: .Immutable).`
16950
+ );
16951
+ }
16952
+ }
16953
+ }
16870
16954
  if (modifiers.has("sealed")) {
16871
16955
  diagnose(
16872
16956
  diagnostics,
@@ -17049,13 +17133,14 @@ function validateConcreteClass(ref, environment, diagnostics) {
17049
17133
  const requiredContracts = allRequiredInterfaceMembers(ref, environment);
17050
17134
  for (const required2 of requiredContracts.values()) {
17051
17135
  const implementation = effective.get(required2.member.name.toLowerCase());
17052
- if (implementation && !implementation.member.modifiers.includes("abstract") && !implementation.member.modifiers.includes("static") && memberCompatibility(
17136
+ const mismatch = implementation ? memberCompatibility(
17053
17137
  implementation.member,
17054
17138
  implementation.substitution,
17055
17139
  required2,
17056
17140
  true,
17057
17141
  environment
17058
- ) === null) {
17142
+ ) : null;
17143
+ if (implementation && !implementation.member.modifiers.includes("abstract") && !implementation.member.modifiers.includes("static") && mismatch === null) {
17059
17144
  continue;
17060
17145
  }
17061
17146
  diagnose(
@@ -17063,7 +17148,7 @@ function validateConcreteClass(ref, environment, diagnostics) {
17063
17148
  ref.uri,
17064
17149
  ref.declaration.nameRange,
17065
17150
  "interface-member-not-implemented",
17066
- implementation ? `Class '${ref.declaration.name}' member '${implementation.member.name}' does not match interface contract '${required2.owner.declaration.name}.${required2.member.name}'.` : `Class '${ref.declaration.name}' does not implement interface member '${required2.owner.declaration.name}.${required2.member.name}'.`,
17151
+ implementation ? implementation.member.modifiers.includes("readonly") && mismatch === "the implementation must provide a setter" ? `Read-only member '${ref.declaration.name}.${implementation.member.name}' cannot implement settable interface member '${required2.owner.declaration.name}.${required2.member.name}'.` : `Class '${ref.declaration.name}' member '${implementation.member.name}' does not match interface contract '${required2.owner.declaration.name}.${required2.member.name}'${mismatch ? `: ${mismatch}` : ""}.` : `Class '${ref.declaration.name}' does not implement interface member '${required2.owner.declaration.name}.${required2.member.name}'.`,
17067
17152
  [
17068
17153
  {
17069
17154
  location: interfaceMemberLocation(required2),
@@ -17239,13 +17324,45 @@ function memberCompatibility(implementation, implementationSubstitution, target,
17239
17324
  return null;
17240
17325
  }
17241
17326
  function valueAccessors(member) {
17242
- if (member.kind === "field") return { get: true, set: true };
17327
+ if (member.kind === "field") {
17328
+ return {
17329
+ get: true,
17330
+ set: !member.modifiers.includes("readonly")
17331
+ };
17332
+ }
17243
17333
  if (member.kind === "function") return { get: false, set: false };
17244
17334
  return {
17245
17335
  get: /\bget\b/.test(member.body.text),
17246
17336
  set: /\bset\b/.test(member.body.text)
17247
17337
  };
17248
17338
  }
17339
+ function resolvedSourceMemberStorage(owner, member, environment, seen = /* @__PURE__ */ new Set()) {
17340
+ const own = member.annotations.find(
17341
+ (annotation2) => annotation2.name === "storage"
17342
+ );
17343
+ if (own) {
17344
+ const allowed = own.arguments.find((argument2) => argument2.name === "allowed") ?? own.arguments[0];
17345
+ const normalized = allowed?.text.replace(/\s+/g, "").toLowerCase();
17346
+ if (normalized === ".immutable") return "immutable";
17347
+ if (normalized === ".save") return "save";
17348
+ if (normalized === ".session") return "session";
17349
+ return null;
17350
+ }
17351
+ if (!member.modifiers.includes("override")) return null;
17352
+ const key = `${owner.declaration.name}:${member.name}`;
17353
+ if (seen.has(key)) return null;
17354
+ seen.add(key);
17355
+ const candidates = inheritedClassMembers(owner, environment).filter(
17356
+ (candidate) => namesEqual(candidate.member.name, member.name)
17357
+ );
17358
+ const target = candidates[candidates.length - 1];
17359
+ return target ? resolvedSourceMemberStorage(
17360
+ target.owner,
17361
+ target.member,
17362
+ environment,
17363
+ seen
17364
+ ) : null;
17365
+ }
17249
17366
  function isTypeAssignable(actual, expected, environment, genericParameters) {
17250
17367
  if (actual.nullable && !expected.nullable) return false;
17251
17368
  if (typesEqual({ ...actual, nullable: false }, { ...expected, nullable: false })) {
@@ -18867,6 +18984,8 @@ function attachConstructorSignature(type, environment) {
18867
18984
  type.id,
18868
18985
  type.members,
18869
18986
  (memberId) => {
18987
+ const declarationMember = environment.members.get(memberId);
18988
+ if (declarationMember?.isReadOnly === true) return null;
18870
18989
  const member = effectiveConstructorMember(
18871
18990
  memberId,
18872
18991
  genericEnvironment,
@@ -19131,6 +19250,7 @@ function memberSymbol(member, schemaKey, environment, field) {
19131
19250
  const kind = string2(member.kind, `${field}.kind`);
19132
19251
  const modifier = string2(member.modifier, `${field}.modifier`);
19133
19252
  const isStatic = boolean(member.isStatic, `${field}.isStatic`);
19253
+ const isReadOnly = boolean(member.isReadOnly, `${field}.isReadOnly`);
19134
19254
  const owner = optionalRecord(member.owner);
19135
19255
  const ownerClassId2 = owner?.kind === "classMember" && typeof owner.classId === "string" ? owner.classId : void 0;
19136
19256
  const type = memberType(member, environment, /* @__PURE__ */ new Set(), field);
@@ -19151,6 +19271,7 @@ function memberSymbol(member, schemaKey, environment, field) {
19151
19271
  type,
19152
19272
  documentation: `${String(member.name ?? schemaKey)} (${id2})`,
19153
19273
  ...isStatic ? { static: true } : {},
19274
+ ...isReadOnly ? { readonlyDeclaration: true } : {},
19154
19275
  ...location3,
19155
19276
  ...scriptDefinitionLocations(member, environment, field),
19156
19277
  ...modifier.includes("abstract") ? { abstract: true } : {},
@@ -19182,9 +19303,9 @@ function memberSymbol(member, schemaKey, environment, field) {
19182
19303
  writable: false
19183
19304
  };
19184
19305
  }
19185
- const writable = kind === "computed" ? computedHasSetter(member, field) : modifier !== "abstract" && member.locked !== true;
19306
+ const writable = isReadOnly ? false : kind === "computed" ? computedHasSetter(member, field) : modifier !== "abstract" && member.locked !== true;
19186
19307
  const storage = typeof member.storage === "string" ? member.storage : void 0;
19187
- const writability = kind === "computed" ? writable ? "setter" : "readOnly" : !writable ? "readOnly" : storage === "immutable" || storage === "save" || storage === "session" ? storage : isStatic && ownerClassId2 ? staticDefaultWritability(ownerClassId2, environment) : void 0;
19308
+ const writability = isReadOnly ? "readOnly" : kind === "computed" ? writable ? "setter" : "readOnly" : !writable ? "readOnly" : storage === "immutable" || storage === "save" || storage === "session" ? storage : isStatic && ownerClassId2 ? staticDefaultWritability(ownerClassId2, environment) : void 0;
19188
19309
  const lookupCollectionMemberId = kind === "lookup" ? string2(member.collectionMemberId, `${field}.collectionMemberId`) : null;
19189
19310
  const lookupCollectionWritability = lookupCollectionMemberId === null ? void 0 : environment.effectiveWritabilityByMemberId.get(
19190
19311
  lookupCollectionMemberId
@@ -20328,6 +20449,7 @@ function projectCompletions(analysis, document, position) {
20328
20449
  "sealed",
20329
20450
  "native",
20330
20451
  "override",
20452
+ "readonly",
20331
20453
  "virtual",
20332
20454
  "static",
20333
20455
  "new",
@@ -21261,7 +21383,7 @@ function constructorArgumentType(analysis, frame) {
21261
21383
  return null;
21262
21384
  }
21263
21385
  const fields = declaration.members.filter(
21264
- (member) => member.kind === "field" && !member.modifiers.includes("static")
21386
+ (member) => member.kind === "field" && !member.modifiers.includes("static") && !member.modifiers.includes("readonly")
21265
21387
  );
21266
21388
  if (frame.argumentName !== null) {
21267
21389
  return fields.find((field) => field.name === frame.argumentName)?.type ?? null;
@@ -21316,7 +21438,7 @@ function projectConstructorParameters(analysis, typeName) {
21316
21438
  function declarationConstructorParameters(declaration) {
21317
21439
  if (declaration.kind === "global" || declaration.kind === "enum") return [];
21318
21440
  return declaration.members.filter(
21319
- (member) => member.kind === "field" && !member.modifiers.includes("static")
21441
+ (member) => member.kind === "field" && !member.modifiers.includes("static") && !member.modifiers.includes("readonly")
21320
21442
  ).map((member) => ({ type: member.type.name, name: member.name }));
21321
21443
  }
21322
21444
  function graphConstructorParameters(typeName) {
@@ -22252,6 +22374,11 @@ function memberFromDocument(record3, members, owners, classNames, context) {
22252
22374
  record3,
22253
22375
  "isAbstract"
22254
22376
  );
22377
+ const isReadOnly = booleanValue(
22378
+ data.isReadOnly ?? false,
22379
+ record3,
22380
+ "isReadOnly"
22381
+ );
22255
22382
  const modifier = memberModifier(overrideOf, isVirtual, isAbstract);
22256
22383
  const defaultValue = defaultValueFromDocument(
22257
22384
  field("defaultValue", null),
@@ -22265,6 +22392,7 @@ function memberFromDocument(record3, members, owners, classNames, context) {
22265
22392
  name: requiredString(data, "name", record3),
22266
22393
  ...docsText === void 0 ? {} : { docsText },
22267
22394
  isStatic: booleanValue(data.isStatic, record3, "isStatic"),
22395
+ isReadOnly,
22268
22396
  accessModifier: accessModifierValue(
22269
22397
  data.accessModifierKind,
22270
22398
  record3,
@@ -22513,6 +22641,7 @@ function memberToDocumentFields(member, baseData3) {
22513
22641
  locked: member.locked,
22514
22642
  required: member.required,
22515
22643
  isStatic: member.isStatic,
22644
+ ...member.isReadOnly ? { isReadOnly: true } : {},
22516
22645
  accessModifierKind: member.accessModifier,
22517
22646
  ...member.docsText === void 0 ? {} : { docsText: member.docsText }
22518
22647
  };
@@ -24981,6 +25110,7 @@ function assertMember2(value, path) {
24981
25110
  }
24982
25111
  nonEmptyString(member.name, `${path}.name`);
24983
25112
  booleanAt(member.isStatic, `${path}.isStatic`);
25113
+ booleanAt(member.isReadOnly, `${path}.isReadOnly`);
24984
25114
  stringIn(
24985
25115
  member.accessModifier,
24986
25116
  /* @__PURE__ */ new Set(["public", "protected", "private"]),
@@ -25015,6 +25145,32 @@ function assertMember2(value, path) {
25015
25145
  assertSystem(member.system, `${path}.system`);
25016
25146
  nullableStorage(member.storage, `${path}.storage`);
25017
25147
  nullableNonEmptyString(member.storageKey, `${path}.storageKey`);
25148
+ if (member.isReadOnly === true) {
25149
+ if (owner.kind !== "classMember" && owner.kind !== "sharedClassMember") {
25150
+ invalid(
25151
+ `${path}.isReadOnly`,
25152
+ "is allowed only on a concrete class field."
25153
+ );
25154
+ }
25155
+ if (member.isStatic === true) {
25156
+ invalid(`${path}.isReadOnly`, "cannot be combined with isStatic.");
25157
+ }
25158
+ if (kind === "computed" || kind === "function" || kind === "scriptFunction") {
25159
+ invalid(
25160
+ `${path}.isReadOnly`,
25161
+ `is not valid on value-less member kind ${JSON.stringify(kind)}.`
25162
+ );
25163
+ }
25164
+ if (member.modifier === "abstract" || member.modifier === "abstractOverride") {
25165
+ invalid(`${path}.isReadOnly`, "cannot be combined with abstract.");
25166
+ }
25167
+ if (member.storage !== "immutable") {
25168
+ invalid(`${path}.storage`, "must be immutable when isReadOnly is true.");
25169
+ }
25170
+ if (member.defaultValue === null) {
25171
+ invalid(`${path}.defaultValue`, "is required when isReadOnly is true.");
25172
+ }
25173
+ }
25018
25174
  if (kind === "int") {
25019
25175
  nullableNumber(member.min, `${path}.min`);
25020
25176
  nullableNumber(member.max, `${path}.max`);
@@ -25023,6 +25179,9 @@ function assertMember2(value, path) {
25023
25179
  if (kind === "string") {
25024
25180
  booleanAt(member.localizable, `${path}.localizable`);
25025
25181
  booleanAt(member.searchKey, `${path}.searchKey`);
25182
+ if (member.isReadOnly === true && member.searchKey === true) {
25183
+ invalid(`${path}.searchKey`, "cannot be true on a read-only member.");
25184
+ }
25026
25185
  return;
25027
25186
  }
25028
25187
  if (kind === "float") {
@@ -25051,6 +25210,9 @@ function assertMember2(value, path) {
25051
25210
  );
25052
25211
  arrayOf(member.indexes, `${path}.indexes`, assertListIndex);
25053
25212
  arrayOf(member.columns, `${path}.columns`, assertListColumn);
25213
+ if (member.isReadOnly === true && Array.isArray(member.indexes) && member.indexes.length > 0) {
25214
+ invalid(`${path}.indexes`, "must be empty on a read-only member.");
25215
+ }
25054
25216
  return;
25055
25217
  }
25056
25218
  if (kind === "class") {
@@ -26236,6 +26398,7 @@ var init_validate = __esm({
26236
26398
  "owner",
26237
26399
  "name",
26238
26400
  "isStatic",
26401
+ "isReadOnly",
26239
26402
  "accessModifier",
26240
26403
  "modifier",
26241
26404
  "locked",
@@ -28053,6 +28216,7 @@ function memberCommon(context, ownerClass, declaration, id2, owner, base) {
28053
28216
  name: declaration.name,
28054
28217
  ...declaration.docsText === void 0 ? {} : { docsText: declaration.docsText },
28055
28218
  isStatic: declaration.modifiers.includes("static"),
28219
+ isReadOnly: declaration.modifiers.includes("readonly"),
28056
28220
  // Non-class placements (collection entries, generic arguments, loose
28057
28221
  // members) have no receiver type to scope visibility to; they are
28058
28222
  // structurally public. Class schema entries apply the C# omission default.
@@ -28068,7 +28232,7 @@ function memberCommon(context, ownerClass, declaration, id2, owner, base) {
28068
28232
  };
28069
28233
  }
28070
28234
  function lowerFieldMember(context, ownerClass, declaration, id2, commonInput, base) {
28071
- const storedStatic = declaration.modifiers.includes("static");
28235
+ const storedStatic = declaration.modifiers.includes("static") && !declaration.modifiers.includes("readonly");
28072
28236
  const settings = annotation(declaration.annotations, "settings");
28073
28237
  const storesSelectionArray = context.enumIdsByName.has(declaration.type.name) || declaration.type.name === "Dialogue" || Boolean(settings && argument(settings, "collection"));
28074
28238
  const common = {
@@ -29898,7 +30062,8 @@ function memberModifier3(member) {
29898
30062
  const accessPrefix = `${member.accessModifier} `;
29899
30063
  const staticPrefix = member.isStatic ? "static " : "";
29900
30064
  const modifier = member.modifier === "plain" ? "" : member.modifier === "abstractOverride" ? "abstract override " : member.modifier === "sealedOverride" ? "override " : `${member.modifier} `;
29901
- return `${accessPrefix}${staticPrefix}${modifier}`;
30065
+ const readOnlyPrefix = member.isReadOnly ? "readonly " : "";
30066
+ return `${accessPrefix}${staticPrefix}${modifier}${readOnlyPrefix}`;
29902
30067
  }
29903
30068
  function renderExtendsGenericBindings(context, schemaClass2, base) {
29904
30069
  if (base.genericParameters.length === 0) return "";
@@ -33137,6 +33302,9 @@ function isNSPointerKeyOf(value) {
33137
33302
  const v = value;
33138
33303
  if (v?.type !== "keyOf" /* keyOf */) return false;
33139
33304
  if (!isNSKeyOf(v.keyOf)) return false;
33305
+ if (v.memberId !== void 0 && typeof v.memberId !== "string") {
33306
+ return false;
33307
+ }
33140
33308
  if (v.optional !== void 0 && typeof v.optional !== "boolean") {
33141
33309
  return false;
33142
33310
  }
@@ -33296,6 +33464,9 @@ function isNSConditionalBranch(value) {
33296
33464
  function isNSFunctionWithReturnType(value) {
33297
33465
  const v = value;
33298
33466
  if (typeof v !== "object" || v === null) return false;
33467
+ if (v.compilerRevision !== void 0 && (!Number.isSafeInteger(v.compilerRevision) || v.compilerRevision < 1 || v.compilerRevision > NEOSCRIPT_COMPILER_REVISION)) {
33468
+ return false;
33469
+ }
33299
33470
  if (!Array.isArray(v.parameters)) return false;
33300
33471
  if (!v.parameters.every(isNSVariable)) return false;
33301
33472
  if (!isNSInstructions(v.instructions)) return false;
@@ -33544,6 +33715,7 @@ var NS_STRING_OPS, NS_DECIMAL_OPS;
33544
33715
  var init_neoscript_guards = __esm({
33545
33716
  "../src/models/neoscript/neoscript-guards.ts"() {
33546
33717
  "use strict";
33718
+ init_src();
33547
33719
  init_member_kinds();
33548
33720
  init_core();
33549
33721
  init_neoscript_types();
@@ -33563,292 +33735,6 @@ var init_neoscript_guards = __esm({
33563
33735
  }
33564
33736
  });
33565
33737
 
33566
- // ../src/models/classes/classes.ts
33567
- function isGenericParamConstraint(value) {
33568
- const v = value;
33569
- if (!v || typeof v !== "object") return false;
33570
- if (v.kind === "class") {
33571
- if (typeof v.classId !== "string") return false;
33572
- if (v.classId.length === 0) return false;
33573
- return v.enumId === void 0;
33574
- }
33575
- if (v.kind === "enum") {
33576
- if (typeof v.enumId !== "string") return false;
33577
- if (v.enumId.length === 0) return false;
33578
- return v.classId === void 0;
33579
- }
33580
- return false;
33581
- }
33582
- function isGenericParamDeclaration(value) {
33583
- const v = value;
33584
- if (!v || typeof v !== "object") return false;
33585
- if (typeof v.id !== "string") return false;
33586
- if (v.id.length === 0) return false;
33587
- if (typeof v.name !== "string") return false;
33588
- if (v.name.length === 0) return false;
33589
- if (v.constraint === void 0 || v.constraint === null) return true;
33590
- return isGenericParamConstraint(v.constraint);
33591
- }
33592
- function isGenericBinding(value) {
33593
- const v = value;
33594
- if (!v || typeof v !== "object") return false;
33595
- if (v.kind === "generic") {
33596
- if (typeof v.genericParamId !== "string") return false;
33597
- if (v.genericParamId.length === 0) return false;
33598
- return v.memberId === void 0;
33599
- }
33600
- if (v.kind === "member") {
33601
- if (typeof v.memberId !== "string") return false;
33602
- if (v.memberId.length === 0) return false;
33603
- return v.genericParamId === void 0;
33604
- }
33605
- return false;
33606
- }
33607
- function isGenericBindingsRecord(value) {
33608
- if (value === null) return false;
33609
- if (typeof value !== "object") return false;
33610
- if (Array.isArray(value)) return false;
33611
- return Object.values(value).every(isGenericBinding);
33612
- }
33613
- function isNeoSchemaClassBase(value) {
33614
- const v = value;
33615
- return typeof v?.name === "string" && isValidDocsText(v.docsText) && isClassSchema(v?.schema) && isOptionalSchemaKeyOrder(v?.schemaKeyOrder) && (v.implementsInterfaceIds === void 0 || v.implementsInterfaceIds === null || Array.isArray(v.implementsInterfaceIds) && v.implementsInterfaceIds.every(
33616
- (interfaceId) => typeof interfaceId === "string" && interfaceId.length > 0
33617
- )) && typeof v?.hiddenInMemberSelector === "boolean" && typeof v?.isAbstract === "boolean" && (v.allowedStorage === void 0 || v.allowedStorage === null || isEffectiveMemberStorage(v.allowedStorage)) && (v.allowedStorageKeys === void 0 || v.allowedStorageKeys === null || Array.isArray(v.allowedStorageKeys) && v.allowedStorageKeys.every((key) => typeof key === "string")) && (v.genericParams === void 0 || v.genericParams === null || Array.isArray(v.genericParams) && v.genericParams.every(isGenericParamDeclaration)) && (v.extendsGenericBindings === void 0 || v.extendsGenericBindings === null || isGenericBindingsRecord(v.extendsGenericBindings)) && (v.system === void 0 || v.system === null || isSystemMetadata(v.system));
33618
- }
33619
- function resolveAllowedStorage(classId, classes, draft) {
33620
- const visited = /* @__PURE__ */ new Set();
33621
- const lookup = (id2) => draft && draft.id === id2 ? draft : classes.find((candidate) => candidate.id === id2);
33622
- let current = lookup(classId);
33623
- while (current) {
33624
- if (visited.has(current.id)) return null;
33625
- visited.add(current.id);
33626
- if (current.allowedStorage != null) return current.allowedStorage;
33627
- if (!current.extendsClassId) return null;
33628
- current = lookup(current.extendsClassId);
33629
- }
33630
- return null;
33631
- }
33632
- function dedupeSchemaKeyOrder(order) {
33633
- const seen = /* @__PURE__ */ new Set();
33634
- const result = [];
33635
- for (const schemaKey of order) {
33636
- if (seen.has(schemaKey)) continue;
33637
- seen.add(schemaKey);
33638
- result.push(schemaKey);
33639
- }
33640
- return result;
33641
- }
33642
- function getClassSchemaKeyOrder(schemaClass2) {
33643
- const schemaKeys = Object.keys(schemaClass2.schema);
33644
- if (schemaClass2.schemaKeyOrder === void 0) return schemaKeys;
33645
- const orderedKeys2 = dedupeSchemaKeyOrder(schemaClass2.schemaKeyOrder);
33646
- const seen = new Set(orderedKeys2);
33647
- for (const schemaKey of schemaKeys) {
33648
- if (seen.has(schemaKey)) continue;
33649
- seen.add(schemaKey);
33650
- orderedKeys2.push(schemaKey);
33651
- }
33652
- return orderedKeys2;
33653
- }
33654
- function isClassSchema(value) {
33655
- if (value === null) return false;
33656
- if (typeof value !== "object") return false;
33657
- if (Array.isArray(value)) return false;
33658
- return Object.values(value).every(
33659
- (schemaValue) => typeof schemaValue === "string"
33660
- );
33661
- }
33662
- function isOptionalSchemaKeyOrder(value) {
33663
- if (value === void 0) return true;
33664
- if (!Array.isArray(value)) return false;
33665
- return value.every((key) => typeof key === "string");
33666
- }
33667
- function isNeoSchemaClassProps(value) {
33668
- const v = value;
33669
- return isNeoSchemaClassBase(value) && typeof v?.id === "string" && isEpochMillis(v?.createdAt) && isEpochMillis(v?.updatedAt) && typeof v?.projectId === "string";
33670
- }
33671
- function isNeoSchemaClass(value) {
33672
- return isNeoSchemaClassProps(value);
33673
- }
33674
- var init_classes = __esm({
33675
- "../src/models/classes/classes.ts"() {
33676
- "use strict";
33677
- init_core();
33678
- init_docs_text2();
33679
- init_member_storage();
33680
- }
33681
- });
33682
-
33683
- // ../src/models/classes/inheritance.ts
33684
- function resolveInheritanceChain(classId, classes, draft) {
33685
- const chain = [];
33686
- const visited = /* @__PURE__ */ new Set();
33687
- const lookup = (id2) => draft && draft.id === id2 ? draft : classes.find((t) => t.id === id2);
33688
- let current = lookup(classId);
33689
- while (current) {
33690
- if (visited.has(current.id)) {
33691
- throw new CircularInheritanceError(
33692
- current.id,
33693
- chain.map((c) => c.id)
33694
- );
33695
- }
33696
- visited.add(current.id);
33697
- chain.push(current);
33698
- if (!current.extendsClassId) break;
33699
- current = lookup(current.extendsClassId);
33700
- }
33701
- return chain;
33702
- }
33703
- function mergeSchemas(chain) {
33704
- const baseFirst = [...chain].reverse();
33705
- const map = /* @__PURE__ */ new Map();
33706
- const order = [];
33707
- for (const schemaClass2 of baseFirst) {
33708
- const localKeys = getClassSchemaKeyOrder(schemaClass2);
33709
- if (schemaClass2.schemaKeyOrder !== void 0) {
33710
- order.splice(
33711
- 0,
33712
- order.length,
33713
- ...localKeys,
33714
- ...order.filter((key) => !localKeys.includes(key))
33715
- );
33716
- }
33717
- for (const key of localKeys) {
33718
- if (!order.includes(key)) order.push(key);
33719
- }
33720
- for (const [key, memberId] of Object.entries(schemaClass2.schema)) {
33721
- map.set(key, {
33722
- schemaKey: key,
33723
- memberId,
33724
- ownerClassId: schemaClass2.id
33725
- });
33726
- }
33727
- }
33728
- return order.flatMap((k) => {
33729
- const entry = map.get(k);
33730
- return entry ? [entry] : [];
33731
- });
33732
- }
33733
- function mergeInstanceSchema(classId, classes, members) {
33734
- const membersById = new Map(members.map((member) => [member.id, member]));
33735
- return mergeSchemas(resolveInheritanceChain(classId, classes)).filter(
33736
- (entry) => membersById.get(entry.memberId)?.isStatic !== true
33737
- );
33738
- }
33739
- function findSchemaPlacement(memberId, classes) {
33740
- for (const schemaClass2 of classes) {
33741
- for (const [key, placedMemberId] of Object.entries(schemaClass2.schema)) {
33742
- if (placedMemberId === memberId) {
33743
- return { ownerClass: schemaClass2, schemaKey: key };
33744
- }
33745
- }
33746
- }
33747
- return null;
33748
- }
33749
- function walkExtendsMemberChain(startId, members, pick, options) {
33750
- const requireKind = options?.requireKind;
33751
- const maxHops = options?.maxHops ?? 16;
33752
- let cursor = members.find((a) => a.id === startId);
33753
- for (let i = 0; cursor && i < maxHops; i++) {
33754
- if (requireKind !== void 0 && cursor.kind !== requireKind) {
33755
- return void 0;
33756
- }
33757
- const v = pick(cursor);
33758
- if (v !== void 0) return v;
33759
- const nextId = getOptionalString(cursor, "extendsMemberId");
33760
- if (nextId === void 0) return void 0;
33761
- cursor = members.find((a) => a.id === nextId);
33762
- }
33763
- return void 0;
33764
- }
33765
- function resolveMember2(member, members) {
33766
- const chain = [];
33767
- const visited = /* @__PURE__ */ new Set();
33768
- let current = member;
33769
- while (current) {
33770
- const id2 = getOptionalString(current, "id");
33771
- if (id2 !== void 0) {
33772
- if (visited.has(id2)) {
33773
- throw new CircularInheritanceError(id2, [...visited]);
33774
- }
33775
- visited.add(id2);
33776
- }
33777
- chain.push(current);
33778
- if (!isMemberOverrideMarker(current)) break;
33779
- const parentId = current.extendsMemberId;
33780
- current = members.find((a) => a.id === parentId);
33781
- }
33782
- const tail = chain[chain.length - 1];
33783
- if (!tail || isMemberOverrideMarker(tail)) {
33784
- const startId = getOptionalString(member, "id") ?? "(unknown)";
33785
- throw new UnresolvedMemberInheritanceError(startId);
33786
- }
33787
- const baseFirst = [...chain].reverse();
33788
- const merged = {};
33789
- for (const link of baseFirst) {
33790
- for (const [key, value] of Object.entries(link)) {
33791
- if (value === void 0) continue;
33792
- merged[key] = value;
33793
- }
33794
- }
33795
- delete merged.extendsMemberId;
33796
- if (member.isAbstract === void 0) {
33797
- delete merged.isAbstract;
33798
- } else {
33799
- merged.isAbstract = member.isAbstract;
33800
- }
33801
- return merged;
33802
- }
33803
- function descendantClassIds(classId, allClasses) {
33804
- const result = /* @__PURE__ */ new Set();
33805
- let added = true;
33806
- while (added) {
33807
- added = false;
33808
- for (const t of allClasses) {
33809
- if (t.id === classId) continue;
33810
- if (result.has(t.id)) continue;
33811
- if (t.extendsClassId === classId || t.extendsClassId && result.has(t.extendsClassId)) {
33812
- result.add(t.id);
33813
- added = true;
33814
- }
33815
- }
33816
- }
33817
- return result;
33818
- }
33819
- var CircularInheritanceError, UnresolvedMemberInheritanceError;
33820
- var init_inheritance = __esm({
33821
- "../src/models/classes/inheritance.ts"() {
33822
- "use strict";
33823
- init_member_kinds();
33824
- init_core();
33825
- init_structural_narrow();
33826
- init_classes();
33827
- CircularInheritanceError = class extends Error {
33828
- constructor(nodeId, chain) {
33829
- super(
33830
- `Circular inheritance detected at "${nodeId}"; chain: ${chain.join(" -> ")}`
33831
- );
33832
- this.nodeId = nodeId;
33833
- this.chain = chain;
33834
- this.name = "CircularInheritanceError";
33835
- }
33836
- nodeId;
33837
- chain;
33838
- };
33839
- UnresolvedMemberInheritanceError = class extends Error {
33840
- constructor(memberId) {
33841
- super(
33842
- `Inheritance chain for member "${memberId}" did not terminate at a non-override member`
33843
- );
33844
- this.memberId = memberId;
33845
- this.name = "UnresolvedMemberInheritanceError";
33846
- }
33847
- memberId;
33848
- };
33849
- }
33850
- });
33851
-
33852
33738
  // ../src/models/interfaces/interface-graph.ts
33853
33739
  function resolveInterfaceClosure(interfaceId, interfaces) {
33854
33740
  const byId = new Map(
@@ -33983,6 +33869,123 @@ var init_neoscript = __esm({
33983
33869
  }
33984
33870
  });
33985
33871
 
33872
+ // ../src/models/classes/classes.ts
33873
+ function isGenericParamConstraint(value) {
33874
+ const v = value;
33875
+ if (!v || typeof v !== "object") return false;
33876
+ if (v.kind === "class") {
33877
+ if (typeof v.classId !== "string") return false;
33878
+ if (v.classId.length === 0) return false;
33879
+ return v.enumId === void 0;
33880
+ }
33881
+ if (v.kind === "enum") {
33882
+ if (typeof v.enumId !== "string") return false;
33883
+ if (v.enumId.length === 0) return false;
33884
+ return v.classId === void 0;
33885
+ }
33886
+ return false;
33887
+ }
33888
+ function isGenericParamDeclaration(value) {
33889
+ const v = value;
33890
+ if (!v || typeof v !== "object") return false;
33891
+ if (typeof v.id !== "string") return false;
33892
+ if (v.id.length === 0) return false;
33893
+ if (typeof v.name !== "string") return false;
33894
+ if (v.name.length === 0) return false;
33895
+ if (v.constraint === void 0 || v.constraint === null) return true;
33896
+ return isGenericParamConstraint(v.constraint);
33897
+ }
33898
+ function isGenericBinding(value) {
33899
+ const v = value;
33900
+ if (!v || typeof v !== "object") return false;
33901
+ if (v.kind === "generic") {
33902
+ if (typeof v.genericParamId !== "string") return false;
33903
+ if (v.genericParamId.length === 0) return false;
33904
+ return v.memberId === void 0;
33905
+ }
33906
+ if (v.kind === "member") {
33907
+ if (typeof v.memberId !== "string") return false;
33908
+ if (v.memberId.length === 0) return false;
33909
+ return v.genericParamId === void 0;
33910
+ }
33911
+ return false;
33912
+ }
33913
+ function isGenericBindingsRecord(value) {
33914
+ if (value === null) return false;
33915
+ if (typeof value !== "object") return false;
33916
+ if (Array.isArray(value)) return false;
33917
+ return Object.values(value).every(isGenericBinding);
33918
+ }
33919
+ function isNeoSchemaClassBase(value) {
33920
+ const v = value;
33921
+ return typeof v?.name === "string" && isValidDocsText(v.docsText) && isClassSchema(v?.schema) && isOptionalSchemaKeyOrder(v?.schemaKeyOrder) && (v.implementsInterfaceIds === void 0 || v.implementsInterfaceIds === null || Array.isArray(v.implementsInterfaceIds) && v.implementsInterfaceIds.every(
33922
+ (interfaceId) => typeof interfaceId === "string" && interfaceId.length > 0
33923
+ )) && typeof v?.hiddenInMemberSelector === "boolean" && typeof v?.isAbstract === "boolean" && (v.allowedStorage === void 0 || v.allowedStorage === null || isEffectiveMemberStorage(v.allowedStorage)) && (v.allowedStorageKeys === void 0 || v.allowedStorageKeys === null || Array.isArray(v.allowedStorageKeys) && v.allowedStorageKeys.every((key) => typeof key === "string")) && (v.genericParams === void 0 || v.genericParams === null || Array.isArray(v.genericParams) && v.genericParams.every(isGenericParamDeclaration)) && (v.extendsGenericBindings === void 0 || v.extendsGenericBindings === null || isGenericBindingsRecord(v.extendsGenericBindings)) && (v.system === void 0 || v.system === null || isSystemMetadata(v.system));
33924
+ }
33925
+ function resolveAllowedStorage(classId, classes, draft) {
33926
+ const visited = /* @__PURE__ */ new Set();
33927
+ const lookup = (id2) => draft && draft.id === id2 ? draft : classes.find((candidate) => candidate.id === id2);
33928
+ let current = lookup(classId);
33929
+ while (current) {
33930
+ if (visited.has(current.id)) return null;
33931
+ visited.add(current.id);
33932
+ if (current.allowedStorage != null) return current.allowedStorage;
33933
+ if (!current.extendsClassId) return null;
33934
+ current = lookup(current.extendsClassId);
33935
+ }
33936
+ return null;
33937
+ }
33938
+ function dedupeSchemaKeyOrder(order) {
33939
+ const seen = /* @__PURE__ */ new Set();
33940
+ const result = [];
33941
+ for (const schemaKey of order) {
33942
+ if (seen.has(schemaKey)) continue;
33943
+ seen.add(schemaKey);
33944
+ result.push(schemaKey);
33945
+ }
33946
+ return result;
33947
+ }
33948
+ function getClassSchemaKeyOrder(schemaClass2) {
33949
+ const schemaKeys = Object.keys(schemaClass2.schema);
33950
+ if (schemaClass2.schemaKeyOrder === void 0) return schemaKeys;
33951
+ const orderedKeys2 = dedupeSchemaKeyOrder(schemaClass2.schemaKeyOrder);
33952
+ const seen = new Set(orderedKeys2);
33953
+ for (const schemaKey of schemaKeys) {
33954
+ if (seen.has(schemaKey)) continue;
33955
+ seen.add(schemaKey);
33956
+ orderedKeys2.push(schemaKey);
33957
+ }
33958
+ return orderedKeys2;
33959
+ }
33960
+ function isClassSchema(value) {
33961
+ if (value === null) return false;
33962
+ if (typeof value !== "object") return false;
33963
+ if (Array.isArray(value)) return false;
33964
+ return Object.values(value).every(
33965
+ (schemaValue) => typeof schemaValue === "string"
33966
+ );
33967
+ }
33968
+ function isOptionalSchemaKeyOrder(value) {
33969
+ if (value === void 0) return true;
33970
+ if (!Array.isArray(value)) return false;
33971
+ return value.every((key) => typeof key === "string");
33972
+ }
33973
+ function isNeoSchemaClassProps(value) {
33974
+ const v = value;
33975
+ return isNeoSchemaClassBase(value) && typeof v?.id === "string" && isEpochMillis(v?.createdAt) && isEpochMillis(v?.updatedAt) && typeof v?.projectId === "string";
33976
+ }
33977
+ function isNeoSchemaClass(value) {
33978
+ return isNeoSchemaClassProps(value);
33979
+ }
33980
+ var init_classes = __esm({
33981
+ "../src/models/classes/classes.ts"() {
33982
+ "use strict";
33983
+ init_core();
33984
+ init_docs_text2();
33985
+ init_member_storage();
33986
+ }
33987
+ });
33988
+
33986
33989
  // ../src/models/members/member-kinds.ts
33987
33990
  function isMemberAccessModifierKind(value) {
33988
33991
  if (value === "public") return true;
@@ -34433,6 +34436,9 @@ function isMemberBase(value) {
34433
34436
  if (typeof v.locked !== "boolean") return false;
34434
34437
  if (typeof v.required !== "boolean") return false;
34435
34438
  if (typeof v.isStatic !== "boolean") return false;
34439
+ if (v.isReadOnly !== void 0 && typeof v.isReadOnly !== "boolean") {
34440
+ return false;
34441
+ }
34436
34442
  if (!isMemberAccessModifierKind(v.accessModifierKind)) return false;
34437
34443
  if (v.isVirtual !== void 0 && typeof v.isVirtual !== "boolean") {
34438
34444
  return false;
@@ -34490,6 +34496,9 @@ function isMemberOverrideBase(value) {
34490
34496
  if (v.locked !== void 0 && typeof v.locked !== "boolean") return false;
34491
34497
  if (v.required !== void 0 && typeof v.required !== "boolean") return false;
34492
34498
  if (v.isStatic !== void 0 && v.isStatic !== false) return false;
34499
+ if (v.isReadOnly !== void 0 && typeof v.isReadOnly !== "boolean") {
34500
+ return false;
34501
+ }
34493
34502
  if (!isMemberAccessModifierKind(v.accessModifierKind)) return false;
34494
34503
  if (v.isVirtual !== void 0 && typeof v.isVirtual !== "boolean") {
34495
34504
  return false;
@@ -34674,175 +34683,184 @@ var init_member_kinds = __esm({
34674
34683
  }
34675
34684
  });
34676
34685
 
34677
- // ../src/models/members/member-kinds-db-response.ts
34678
- var init_member_kinds_db_response = __esm({
34679
- "../src/models/members/member-kinds-db-response.ts"() {
34680
- "use strict";
34681
- init_member_kinds();
34682
- }
34683
- });
34684
-
34685
- // ../src/models/members/unordered-list-membership.ts
34686
- var init_unordered_list_membership = __esm({
34687
- "../src/models/members/unordered-list-membership.ts"() {
34688
- "use strict";
34689
- init_member_kinds();
34690
- }
34691
- });
34692
-
34693
- // ../src/models/members/member-storage-key.ts
34694
- function normalizeStorageKeyDeclaration(declaration) {
34695
- if (declaration === void 0 || declaration === null) {
34696
- return STORAGE_KEY_INHERIT;
34697
- }
34698
- if (declaration.length === 0) return STORAGE_KEY_INHERIT;
34699
- if (declaration === STORAGE_KEY_ALL) {
34700
- throw new Error(
34701
- 'Storage key "all" is reserved for partition-scoped reads and cannot be declared on a member.'
34702
- );
34703
- }
34704
- return declaration;
34705
- }
34706
- function storageKeyReferencesParentClass(declaration) {
34707
- return declaration.includes(PARENT_CLASS_TEMPLATE_TOKEN);
34708
- }
34709
- function resolveMapKeyForCreatedValue(args) {
34710
- const declaration = normalizeStorageKeyDeclaration(args.declaration);
34711
- if (declaration === STORAGE_KEY_INHERIT) return args.parentMapKey;
34712
- if (declaration === MAIN_STORAGE_PARTITION) return null;
34713
- if (storageKeyReferencesParentClass(declaration)) {
34714
- if (args.parentClassId === void 0) {
34715
- throw new Error(
34716
- `Storage key "${declaration}" references ${PARENT_CLASS_TEMPLATE_TOKEN}, but the placement parent value has no classId (only class-valued parents can anchor a ${PARENT_CLASS_TEMPLATE_TOKEN} partition).`
34686
+ // ../src/models/classes/inheritance.ts
34687
+ function resolveInheritanceChain(classId, classes, draft) {
34688
+ const chain = [];
34689
+ const visited = /* @__PURE__ */ new Set();
34690
+ const lookup = (id2) => draft && draft.id === id2 ? draft : classes.find((t) => t.id === id2);
34691
+ let current = lookup(classId);
34692
+ while (current) {
34693
+ if (visited.has(current.id)) {
34694
+ throw new CircularInheritanceError(
34695
+ current.id,
34696
+ chain.map((c) => c.id)
34717
34697
  );
34718
34698
  }
34719
- return declaration.replaceAll(
34720
- PARENT_CLASS_TEMPLATE_TOKEN,
34721
- args.parentClassId
34722
- );
34699
+ visited.add(current.id);
34700
+ chain.push(current);
34701
+ if (!current.extendsClassId) break;
34702
+ current = lookup(current.extendsClassId);
34723
34703
  }
34724
- return declaration;
34704
+ return chain;
34725
34705
  }
34726
- var MAIN_STORAGE_PARTITION, STORAGE_KEY_INHERIT, STORAGE_KEY_ALL, PARENT_CLASS_TEMPLATE_TOKEN;
34727
- var init_member_storage_key = __esm({
34728
- "../src/models/members/member-storage-key.ts"() {
34729
- "use strict";
34730
- MAIN_STORAGE_PARTITION = "main";
34731
- STORAGE_KEY_INHERIT = "inherit";
34732
- STORAGE_KEY_ALL = "all";
34733
- PARENT_CLASS_TEMPLATE_TOKEN = "$parentClass";
34734
- }
34735
- });
34736
-
34737
- // ../src/models/members/storage-partitions.ts
34738
- function stampCreatedValuesMapKey(values, mapKey) {
34739
- const normalized = mapKey === void 0 || mapKey === null || mapKey.length === 0 || mapKey === MAIN_STORAGE_PARTITION ? null : mapKey;
34740
- for (const value of values) {
34741
- if (normalized === null) {
34742
- delete value.mapKey;
34743
- } else {
34744
- value.mapKey = normalized;
34706
+ function mergeSchemas(chain) {
34707
+ const baseFirst = [...chain].reverse();
34708
+ const map = /* @__PURE__ */ new Map();
34709
+ const order = [];
34710
+ for (const schemaClass2 of baseFirst) {
34711
+ const localKeys = getClassSchemaKeyOrder(schemaClass2);
34712
+ if (schemaClass2.schemaKeyOrder !== void 0) {
34713
+ order.splice(
34714
+ 0,
34715
+ order.length,
34716
+ ...localKeys,
34717
+ ...order.filter((key) => !localKeys.includes(key))
34718
+ );
34719
+ }
34720
+ for (const key of localKeys) {
34721
+ if (!order.includes(key)) order.push(key);
34722
+ }
34723
+ for (const [key, memberId] of Object.entries(schemaClass2.schema)) {
34724
+ map.set(key, {
34725
+ schemaKey: key,
34726
+ memberId,
34727
+ ownerClassId: schemaClass2.id
34728
+ });
34745
34729
  }
34746
34730
  }
34731
+ return order.flatMap((k) => {
34732
+ const entry = map.get(k);
34733
+ return entry ? [entry] : [];
34734
+ });
34747
34735
  }
34748
- function applyDeclaredStorageKeyOverrides(args) {
34749
- const createdById = new Map(
34750
- args.createdValues.map((value) => [value.id, value])
34736
+ function mergeInstanceSurfaceSchema(classId, classes, members) {
34737
+ const membersById = new Map(members.map((member) => [member.id, member]));
34738
+ return mergeSchemas(resolveInheritanceChain(classId, classes)).filter(
34739
+ (entry) => membersById.get(entry.memberId)?.isStatic !== true
34751
34740
  );
34752
- const parentOf = /* @__PURE__ */ new Map();
34753
- for (const value of args.createdValues) {
34754
- for (const childId of referencedValueIdCandidates(value.value)) {
34755
- if (createdById.has(childId)) parentOf.set(childId, value);
34741
+ }
34742
+ function mergeStoredInstanceSchema(classId, classes, members) {
34743
+ const membersById = new Map(members.map((member) => [member.id, member]));
34744
+ return mergeInstanceSurfaceSchema(classId, classes, members).filter(
34745
+ (entry) => membersById.get(entry.memberId)?.isReadOnly !== true
34746
+ );
34747
+ }
34748
+ function findSchemaPlacement(memberId, classes) {
34749
+ for (const schemaClass2 of classes) {
34750
+ for (const [key, placedMemberId] of Object.entries(schemaClass2.schema)) {
34751
+ if (placedMemberId === memberId) {
34752
+ return { ownerClass: schemaClass2, schemaKey: key };
34753
+ }
34756
34754
  }
34757
34755
  }
34758
- for (const value of args.createdValues) {
34759
- if (typeof value.containerId !== "string") continue;
34760
- const container = createdById.get(value.containerId);
34761
- if (container !== void 0) parentOf.set(value.id, container);
34762
- }
34763
- const depthOf = (value) => {
34764
- let depth = 0;
34765
- let current = value;
34766
- const seen = /* @__PURE__ */ new Set();
34767
- while (current !== void 0 && !seen.has(current.id)) {
34768
- seen.add(current.id);
34769
- current = parentOf.get(current.id);
34770
- if (current !== void 0) depth += 1;
34771
- }
34772
- return depth;
34773
- };
34774
- const boundaries = args.createdValues.filter((value) => {
34775
- const declaration = normalizeStorageKeyDeclaration(
34776
- args.declarationByValueId.get(value.id)
34777
- );
34778
- return declaration !== STORAGE_KEY_INHERIT;
34779
- }).sort((left, right) => depthOf(left) - depthOf(right));
34780
- for (const boundary of boundaries) {
34781
- const parentCreated = parentOf.get(boundary.id);
34782
- const parent = parentCreated !== void 0 ? {
34783
- mapKey: parentCreated.mapKey ?? null,
34784
- classId: parentCreated.classId ?? void 0
34785
- } : args.existingParentContextById?.get(boundary.id);
34786
- if (parent === void 0) {
34787
- throw new Error(
34788
- `Cannot resolve storage partition for created value "${boundary.id}": its placement parent is neither a created value nor supplied in existingParentContextById.`
34789
- );
34790
- }
34791
- const mapKey = resolveMapKeyForCreatedValue({
34792
- declaration: args.declarationByValueId.get(boundary.id),
34793
- parentMapKey: parent.mapKey,
34794
- parentClassId: parent.classId
34795
- });
34796
- for (const member of collectCreatedSubtreeValues(
34797
- boundary,
34798
- args.createdValues
34799
- )) {
34800
- if (mapKey === null || mapKey === MAIN_STORAGE_PARTITION) {
34801
- delete member.mapKey;
34802
- } else {
34803
- member.mapKey = mapKey;
34804
- }
34756
+ return null;
34757
+ }
34758
+ function walkExtendsMemberChain(startId, members, pick, options) {
34759
+ const requireKind = options?.requireKind;
34760
+ const maxHops = options?.maxHops ?? 16;
34761
+ let cursor = members.find((a) => a.id === startId);
34762
+ for (let i = 0; cursor && i < maxHops; i++) {
34763
+ if (requireKind !== void 0 && cursor.kind !== requireKind) {
34764
+ return void 0;
34805
34765
  }
34766
+ const v = pick(cursor);
34767
+ if (v !== void 0) return v;
34768
+ const nextId = getOptionalString(cursor, "extendsMemberId");
34769
+ if (nextId === void 0) return void 0;
34770
+ cursor = members.find((a) => a.id === nextId);
34806
34771
  }
34772
+ return void 0;
34807
34773
  }
34808
- function collectCreatedSubtreeValues(root, createdValues) {
34809
- const createdById = new Map(createdValues.map((value) => [value.id, value]));
34810
- const subtree = [];
34774
+ function resolveMember2(member, members) {
34775
+ const chain = [];
34811
34776
  const visited = /* @__PURE__ */ new Set();
34812
- const queue = [root];
34813
- while (queue.length > 0) {
34814
- const current = queue.shift();
34815
- if (current === void 0) break;
34816
- if (visited.has(current.id)) continue;
34817
- visited.add(current.id);
34818
- subtree.push(current);
34819
- for (const childId of referencedValueIdCandidates(current.value)) {
34820
- const child = createdById.get(childId);
34821
- if (child !== void 0) queue.push(child);
34777
+ let current = member;
34778
+ while (current) {
34779
+ const id2 = getOptionalString(current, "id");
34780
+ if (id2 !== void 0) {
34781
+ if (visited.has(id2)) {
34782
+ throw new CircularInheritanceError(id2, [...visited]);
34783
+ }
34784
+ visited.add(id2);
34822
34785
  }
34823
- for (const candidate of createdValues) {
34824
- if (candidate.containerId === current.id) queue.push(candidate);
34786
+ chain.push(current);
34787
+ if (!isMemberOverrideMarker(current)) break;
34788
+ const parentId = current.extendsMemberId;
34789
+ current = members.find((a) => a.id === parentId);
34790
+ }
34791
+ const tail = chain[chain.length - 1];
34792
+ if (!tail || isMemberOverrideMarker(tail)) {
34793
+ const startId = getOptionalString(member, "id") ?? "(unknown)";
34794
+ throw new UnresolvedMemberInheritanceError(startId);
34795
+ }
34796
+ const baseFirst = [...chain].reverse();
34797
+ const merged = {};
34798
+ for (const link of baseFirst) {
34799
+ for (const [key, value] of Object.entries(link)) {
34800
+ if (value === void 0) continue;
34801
+ merged[key] = value;
34825
34802
  }
34826
34803
  }
34827
- return subtree;
34828
- }
34829
- function referencedValueIdCandidates(value) {
34830
- if (Array.isArray(value)) {
34831
- return value.filter((entry) => typeof entry === "string");
34804
+ delete merged.extendsMemberId;
34805
+ if (member.isAbstract === void 0) {
34806
+ delete merged.isAbstract;
34807
+ } else {
34808
+ merged.isAbstract = member.isAbstract;
34832
34809
  }
34833
- if (typeof value === "object" && value !== null) {
34834
- return Object.values(value).filter(
34835
- (entry) => typeof entry === "string"
34836
- );
34810
+ if (member.isReadOnly === void 0) {
34811
+ delete merged.isReadOnly;
34812
+ } else {
34813
+ merged.isReadOnly = member.isReadOnly;
34837
34814
  }
34838
- return [];
34815
+ return merged;
34839
34816
  }
34840
- var init_storage_partitions = __esm({
34841
- "../src/models/members/storage-partitions.ts"() {
34817
+ function descendantClassIds(classId, allClasses) {
34818
+ const result = /* @__PURE__ */ new Set();
34819
+ let added = true;
34820
+ while (added) {
34821
+ added = false;
34822
+ for (const t of allClasses) {
34823
+ if (t.id === classId) continue;
34824
+ if (result.has(t.id)) continue;
34825
+ if (t.extendsClassId === classId || t.extendsClassId && result.has(t.extendsClassId)) {
34826
+ result.add(t.id);
34827
+ added = true;
34828
+ }
34829
+ }
34830
+ }
34831
+ return result;
34832
+ }
34833
+ var CircularInheritanceError, UnresolvedMemberInheritanceError, mergeInstanceSchema;
34834
+ var init_inheritance = __esm({
34835
+ "../src/models/classes/inheritance.ts"() {
34842
34836
  "use strict";
34843
- init_inheritance();
34844
- init_member_storage_key();
34845
- init_member_storage_key();
34837
+ init_member_kinds();
34838
+ init_core();
34839
+ init_structural_narrow();
34840
+ init_classes();
34841
+ CircularInheritanceError = class extends Error {
34842
+ constructor(nodeId, chain) {
34843
+ super(
34844
+ `Circular inheritance detected at "${nodeId}"; chain: ${chain.join(" -> ")}`
34845
+ );
34846
+ this.nodeId = nodeId;
34847
+ this.chain = chain;
34848
+ this.name = "CircularInheritanceError";
34849
+ }
34850
+ nodeId;
34851
+ chain;
34852
+ };
34853
+ UnresolvedMemberInheritanceError = class extends Error {
34854
+ constructor(memberId) {
34855
+ super(
34856
+ `Inheritance chain for member "${memberId}" did not terminate at a non-override member`
34857
+ );
34858
+ this.memberId = memberId;
34859
+ this.name = "UnresolvedMemberInheritanceError";
34860
+ }
34861
+ memberId;
34862
+ };
34863
+ mergeInstanceSchema = mergeInstanceSurfaceSchema;
34846
34864
  }
34847
34865
  });
34848
34866
 
@@ -35030,6 +35048,11 @@ function substituteMember(member, env, members) {
35030
35048
  } else {
35031
35049
  delete substituted.isAbstract;
35032
35050
  }
35051
+ if (resolved.isReadOnly !== void 0) {
35052
+ substituted.isReadOnly = resolved.isReadOnly;
35053
+ } else {
35054
+ delete substituted.isReadOnly;
35055
+ }
35033
35056
  delete substituted.extendsMemberId;
35034
35057
  return substituted;
35035
35058
  }
@@ -35321,6 +35344,195 @@ var init_generics = __esm({
35321
35344
  }
35322
35345
  });
35323
35346
 
35347
+ // ../src/models/members/read-only-members.ts
35348
+ var VALUELESS_KINDS;
35349
+ var init_read_only_members = __esm({
35350
+ "../src/models/members/read-only-members.ts"() {
35351
+ "use strict";
35352
+ init_inheritance();
35353
+ init_generics();
35354
+ init_member_kinds();
35355
+ init_member_storage();
35356
+ VALUELESS_KINDS = /* @__PURE__ */ new Set([
35357
+ 10 /* NSProperty */,
35358
+ 13 /* Function */,
35359
+ 23 /* NSFunction */
35360
+ ]);
35361
+ }
35362
+ });
35363
+
35364
+ // ../src/models/members/member-kinds-db-response.ts
35365
+ var init_member_kinds_db_response = __esm({
35366
+ "../src/models/members/member-kinds-db-response.ts"() {
35367
+ "use strict";
35368
+ init_member_kinds();
35369
+ }
35370
+ });
35371
+
35372
+ // ../src/models/members/unordered-list-membership.ts
35373
+ var init_unordered_list_membership = __esm({
35374
+ "../src/models/members/unordered-list-membership.ts"() {
35375
+ "use strict";
35376
+ init_member_kinds();
35377
+ }
35378
+ });
35379
+
35380
+ // ../src/models/members/member-storage-key.ts
35381
+ function normalizeStorageKeyDeclaration(declaration) {
35382
+ if (declaration === void 0 || declaration === null) {
35383
+ return STORAGE_KEY_INHERIT;
35384
+ }
35385
+ if (declaration.length === 0) return STORAGE_KEY_INHERIT;
35386
+ if (declaration === STORAGE_KEY_ALL) {
35387
+ throw new Error(
35388
+ 'Storage key "all" is reserved for partition-scoped reads and cannot be declared on a member.'
35389
+ );
35390
+ }
35391
+ return declaration;
35392
+ }
35393
+ function storageKeyReferencesParentClass(declaration) {
35394
+ return declaration.includes(PARENT_CLASS_TEMPLATE_TOKEN);
35395
+ }
35396
+ function resolveMapKeyForCreatedValue(args) {
35397
+ const declaration = normalizeStorageKeyDeclaration(args.declaration);
35398
+ if (declaration === STORAGE_KEY_INHERIT) return args.parentMapKey;
35399
+ if (declaration === MAIN_STORAGE_PARTITION) return null;
35400
+ if (storageKeyReferencesParentClass(declaration)) {
35401
+ if (args.parentClassId === void 0) {
35402
+ throw new Error(
35403
+ `Storage key "${declaration}" references ${PARENT_CLASS_TEMPLATE_TOKEN}, but the placement parent value has no classId (only class-valued parents can anchor a ${PARENT_CLASS_TEMPLATE_TOKEN} partition).`
35404
+ );
35405
+ }
35406
+ return declaration.replaceAll(
35407
+ PARENT_CLASS_TEMPLATE_TOKEN,
35408
+ args.parentClassId
35409
+ );
35410
+ }
35411
+ return declaration;
35412
+ }
35413
+ var MAIN_STORAGE_PARTITION, STORAGE_KEY_INHERIT, STORAGE_KEY_ALL, PARENT_CLASS_TEMPLATE_TOKEN;
35414
+ var init_member_storage_key = __esm({
35415
+ "../src/models/members/member-storage-key.ts"() {
35416
+ "use strict";
35417
+ MAIN_STORAGE_PARTITION = "main";
35418
+ STORAGE_KEY_INHERIT = "inherit";
35419
+ STORAGE_KEY_ALL = "all";
35420
+ PARENT_CLASS_TEMPLATE_TOKEN = "$parentClass";
35421
+ }
35422
+ });
35423
+
35424
+ // ../src/models/members/storage-partitions.ts
35425
+ function stampCreatedValuesMapKey(values, mapKey) {
35426
+ const normalized = mapKey === void 0 || mapKey === null || mapKey.length === 0 || mapKey === MAIN_STORAGE_PARTITION ? null : mapKey;
35427
+ for (const value of values) {
35428
+ if (normalized === null) {
35429
+ delete value.mapKey;
35430
+ } else {
35431
+ value.mapKey = normalized;
35432
+ }
35433
+ }
35434
+ }
35435
+ function applyDeclaredStorageKeyOverrides(args) {
35436
+ const createdById = new Map(
35437
+ args.createdValues.map((value) => [value.id, value])
35438
+ );
35439
+ const parentOf = /* @__PURE__ */ new Map();
35440
+ for (const value of args.createdValues) {
35441
+ for (const childId of referencedValueIdCandidates(value.value)) {
35442
+ if (createdById.has(childId)) parentOf.set(childId, value);
35443
+ }
35444
+ }
35445
+ for (const value of args.createdValues) {
35446
+ if (typeof value.containerId !== "string") continue;
35447
+ const container = createdById.get(value.containerId);
35448
+ if (container !== void 0) parentOf.set(value.id, container);
35449
+ }
35450
+ const depthOf = (value) => {
35451
+ let depth = 0;
35452
+ let current = value;
35453
+ const seen = /* @__PURE__ */ new Set();
35454
+ while (current !== void 0 && !seen.has(current.id)) {
35455
+ seen.add(current.id);
35456
+ current = parentOf.get(current.id);
35457
+ if (current !== void 0) depth += 1;
35458
+ }
35459
+ return depth;
35460
+ };
35461
+ const boundaries = args.createdValues.filter((value) => {
35462
+ const declaration = normalizeStorageKeyDeclaration(
35463
+ args.declarationByValueId.get(value.id)
35464
+ );
35465
+ return declaration !== STORAGE_KEY_INHERIT;
35466
+ }).sort((left, right) => depthOf(left) - depthOf(right));
35467
+ for (const boundary of boundaries) {
35468
+ const parentCreated = parentOf.get(boundary.id);
35469
+ const parent = parentCreated !== void 0 ? {
35470
+ mapKey: parentCreated.mapKey ?? null,
35471
+ classId: parentCreated.classId ?? void 0
35472
+ } : args.existingParentContextById?.get(boundary.id);
35473
+ if (parent === void 0) {
35474
+ throw new Error(
35475
+ `Cannot resolve storage partition for created value "${boundary.id}": its placement parent is neither a created value nor supplied in existingParentContextById.`
35476
+ );
35477
+ }
35478
+ const mapKey = resolveMapKeyForCreatedValue({
35479
+ declaration: args.declarationByValueId.get(boundary.id),
35480
+ parentMapKey: parent.mapKey,
35481
+ parentClassId: parent.classId
35482
+ });
35483
+ for (const member of collectCreatedSubtreeValues(
35484
+ boundary,
35485
+ args.createdValues
35486
+ )) {
35487
+ if (mapKey === null || mapKey === MAIN_STORAGE_PARTITION) {
35488
+ delete member.mapKey;
35489
+ } else {
35490
+ member.mapKey = mapKey;
35491
+ }
35492
+ }
35493
+ }
35494
+ }
35495
+ function collectCreatedSubtreeValues(root, createdValues) {
35496
+ const createdById = new Map(createdValues.map((value) => [value.id, value]));
35497
+ const subtree = [];
35498
+ const visited = /* @__PURE__ */ new Set();
35499
+ const queue = [root];
35500
+ while (queue.length > 0) {
35501
+ const current = queue.shift();
35502
+ if (current === void 0) break;
35503
+ if (visited.has(current.id)) continue;
35504
+ visited.add(current.id);
35505
+ subtree.push(current);
35506
+ for (const childId of referencedValueIdCandidates(current.value)) {
35507
+ const child = createdById.get(childId);
35508
+ if (child !== void 0) queue.push(child);
35509
+ }
35510
+ for (const candidate of createdValues) {
35511
+ if (candidate.containerId === current.id) queue.push(candidate);
35512
+ }
35513
+ }
35514
+ return subtree;
35515
+ }
35516
+ function referencedValueIdCandidates(value) {
35517
+ if (Array.isArray(value)) {
35518
+ return value.filter((entry) => typeof entry === "string");
35519
+ }
35520
+ if (typeof value === "object" && value !== null) {
35521
+ return Object.values(value).filter(
35522
+ (entry) => typeof entry === "string"
35523
+ );
35524
+ }
35525
+ return [];
35526
+ }
35527
+ var init_storage_partitions = __esm({
35528
+ "../src/models/members/storage-partitions.ts"() {
35529
+ "use strict";
35530
+ init_inheritance();
35531
+ init_member_storage_key();
35532
+ init_member_storage_key();
35533
+ }
35534
+ });
35535
+
35324
35536
  // ../src/models/unity/unity-import-settings.ts
35325
35537
  function buildDefaultUnityTexture2DImportSettings() {
35326
35538
  return {
@@ -36450,7 +36662,7 @@ function buildDefaultMemberValue(args) {
36450
36662
  const unboundParamId = firstUnboundParamId(childEnv);
36451
36663
  if (unboundParamId !== null) {
36452
36664
  throw new Error(
36453
- `Cannot create a value of open generic class "${effectiveClass?.name ?? effectiveClassId}": generic param "${unboundParamId}" is unbound \u2014 pick a closed descendant or construct the slot's class arguments (specs/class-generics.md Decision 6).`
36665
+ `Cannot create a value of open generic class "${effectiveClass?.name ?? effectiveClassId}": generic param "${unboundParamId}" is unbound \u2014 pick a closed descendant or construct the slot's class arguments (https://github.com/ryanbliss/neo-compose-specs/tree/main/new-features/complete/class-generics.md Decision 6).`
36454
36666
  );
36455
36667
  }
36456
36668
  if (member.classArguments != null && Object.keys(member.classArguments).length > 0) {
@@ -36467,7 +36679,7 @@ function buildDefaultMemberValue(args) {
36467
36679
  );
36468
36680
  }
36469
36681
  }
36470
- const merged = mergeInstanceSchema(
36682
+ const merged = mergeStoredInstanceSchema(
36471
36683
  effectiveClassId,
36472
36684
  args.document.classes,
36473
36685
  args.document.members
@@ -36773,7 +36985,7 @@ function formatDefaultReferenceLocation(memberName, key) {
36773
36985
  }
36774
36986
  function getSchemaEntryMap(document, classId) {
36775
36987
  return new Map(
36776
- mergeInstanceSchema(classId, document.classes, document.members).map(
36988
+ mergeStoredInstanceSchema(classId, document.classes, document.members).map(
36777
36989
  (entry) => [entry.schemaKey, entry]
36778
36990
  )
36779
36991
  );
@@ -36880,7 +37092,7 @@ function primitiveFallbackValue(document, member) {
36880
37092
  }
36881
37093
  if (member.kind === 21 /* Generic */) {
36882
37094
  throw new Error(
36883
- `Unreachable: Generic member "${member.name}" must be substituted through its binding environment before default value construction \u2014 a substitution site was skipped upstream (specs/class-generics.md \xA74.1).`
37095
+ `Unreachable: Generic member "${member.name}" must be substituted through its binding environment before default value construction \u2014 a substitution site was skipped upstream (https://github.com/ryanbliss/neo-compose-specs/tree/main/new-features/complete/class-generics.md \xA74.1).`
36884
37096
  );
36885
37097
  }
36886
37098
  throw new Error(
@@ -37313,7 +37525,7 @@ var init_effective_storage = __esm({
37313
37525
  }
37314
37526
  /**
37315
37527
  * The set of effective storages of `memberId` across every placement
37316
- * (specs/member-storage.md §2.3, generalized to the placement *graph*).
37528
+ * (https://github.com/ryanbliss/neo-compose-specs/tree/main/new-features/complete/member-storage.md §2.3, generalized to the placement *graph*).
37317
37529
  */
37318
37530
  effectiveStorages(memberId) {
37319
37531
  const cached = this.effectiveByMemberId.get(memberId);
@@ -37711,6 +37923,7 @@ var init_members = __esm({
37711
37923
  "../src/models/members/index.ts"() {
37712
37924
  "use strict";
37713
37925
  init_member_storage();
37926
+ init_read_only_members();
37714
37927
  init_member_kinds();
37715
37928
  init_member_kinds_db_response();
37716
37929
  init_unordered_list_membership();
@@ -52680,7 +52893,13 @@ function evalPointer(pointer, scope, ctx) {
52680
52893
  case "staticMember" /* staticMember */:
52681
52894
  return evalStaticMember(pointer.memberId, ctx);
52682
52895
  case "keyOf" /* keyOf */:
52683
- return evalKeyOf(pointer.keyOf, scope, ctx, pointer.optional === true);
52896
+ return evalKeyOf(
52897
+ pointer.keyOf,
52898
+ scope,
52899
+ ctx,
52900
+ pointer.optional === true,
52901
+ pointer.memberId
52902
+ );
52684
52903
  case "operation" /* operation */:
52685
52904
  return evalOperation(pointer.operation, scope, ctx);
52686
52905
  case "function" /* function */:
@@ -53443,7 +53662,7 @@ function isRuntimeSpriteValue(value) {
53443
53662
  const sliceIndex = value.sliceIndex;
53444
53663
  return typeof sliceIndex === "number" && Number.isInteger(sliceIndex) && sliceIndex >= 0;
53445
53664
  }
53446
- function evalKeyOf(keyOf, scope, ctx, optional = false) {
53665
+ function evalKeyOf(keyOf, scope, ctx, optional = false, memberId) {
53447
53666
  const receiver = evalPointer(keyOf.pointer, scope, ctx);
53448
53667
  if (optional && (receiver === null || receiver === void 0)) {
53449
53668
  return null;
@@ -53491,6 +53710,11 @@ function evalKeyOf(keyOf, scope, ctx, optional = false) {
53491
53710
  if (assetMember.kind === "ok") return assetMember.value;
53492
53711
  const dispatched = dispatchSchemaMember(receiver, k, ctx);
53493
53712
  if (dispatched.kind === "ok") return dispatched.value;
53713
+ if (!dispatched.matchedMember && memberId !== void 0) {
53714
+ const member = evalMemberById(ctx.vm, memberId);
53715
+ const defaultValue = readOnlyDeclarationDefault(member, memberId, ctx);
53716
+ if (defaultValue.matched) return defaultValue.value;
53717
+ }
53494
53718
  if (Object.prototype.hasOwnProperty.call(receiver, k)) {
53495
53719
  const at = receiver[k];
53496
53720
  return resolveValueIfId(at, ctx);
@@ -53503,13 +53727,15 @@ function evalKeyOf(keyOf, scope, ctx, optional = false) {
53503
53727
  }
53504
53728
  function dispatchSchemaMember(receiver, schemaKey, ctx) {
53505
53729
  if (typeof receiver !== "object" || receiver === null) {
53506
- return { kind: "no-info" };
53730
+ return { kind: "no-info", matchedMember: false };
53507
53731
  }
53508
53732
  const member = resolveRuntimeSchemaMember(receiver, schemaKey, ctx);
53509
- if (!member) return { kind: "no-info" };
53733
+ if (!member) return { kind: "no-info", matchedMember: false };
53734
+ const defaultValue = readOnlyDeclarationDefault(member, member.id, ctx);
53735
+ if (defaultValue.matched) return { kind: "ok", value: defaultValue.value };
53510
53736
  if (member.kind === 10 /* NSProperty */) {
53511
53737
  if (!resolveCompiledGetter(member.id, ctx)) {
53512
- return { kind: "no-info" };
53738
+ return { kind: "no-info", matchedMember: true };
53513
53739
  }
53514
53740
  return {
53515
53741
  kind: "ok",
@@ -53517,18 +53743,46 @@ function dispatchSchemaMember(receiver, schemaKey, ctx) {
53517
53743
  };
53518
53744
  }
53519
53745
  if (!Object.prototype.hasOwnProperty.call(receiver, schemaKey)) {
53520
- return { kind: "no-info" };
53746
+ return { kind: "no-info", matchedMember: true };
53521
53747
  }
53522
53748
  const at = receiver[schemaKey];
53523
53749
  return { kind: "ok", value: resolveValueIfIdForMember(at, member, ctx) };
53524
53750
  }
53751
+ function readOnlyDeclarationDefault(member, memberId, ctx) {
53752
+ const readOnly = member?.isReadOnly;
53753
+ if (readOnly !== true) return { matched: false };
53754
+ if (member?.defaultValue === void 0 || member.defaultValue === null) {
53755
+ throw new NSGetterRuntimeError(
53756
+ `Read-only member '${member?.name ?? memberId}' has no declaration default.`
53757
+ );
53758
+ }
53759
+ let value = member.defaultValue.value;
53760
+ if (isMemberString(member) && member.localizable !== false && typeof value === "string") {
53761
+ value = resolveLocalizedTextId(value, ctx);
53762
+ } else if (shouldUnwrapSingleLookupValue(member)) {
53763
+ value = unwrapSingleLookupValue(value, ctx);
53764
+ }
53765
+ return { matched: true, value };
53766
+ }
53525
53767
  function resolveRuntimeSchemaMember(receiver, schemaKey, ctx) {
53526
53768
  if (typeof receiver !== "object" || receiver === null) return null;
53527
53769
  const row = trackedRowForValueReference(receiver, ctx);
53528
- const runtimeClassId = row === null ? void 0 : classIdForValueRow(row, ctx);
53770
+ if (row === null) return null;
53771
+ const runtimeClassId = classIdForValueRow(row, ctx);
53529
53772
  if (!runtimeClassId) return null;
53530
53773
  const memberId = cachedMergedSchemaMemberId(runtimeClassId, schemaKey, ctx);
53531
- return memberId === null ? null : evalMemberById(ctx.vm, memberId);
53774
+ if (memberId === null) return null;
53775
+ const member = evalMemberById(ctx.vm, memberId);
53776
+ if (member === null) return null;
53777
+ if (member.kind !== 21 /* Generic */) return member;
53778
+ const env = runtimeGenericEnvForValueRow(row, ctx, /* @__PURE__ */ new Set());
53779
+ try {
53780
+ return substituteMember(member, env, ctx.vm.members);
53781
+ } catch (error) {
53782
+ throw new NSGetterRuntimeError(
53783
+ `Cannot resolve runtime member '${member.name}' for Class '${runtimeClassId}': ${error instanceof Error ? error.message : String(error)}`
53784
+ );
53785
+ }
53532
53786
  }
53533
53787
  function resolveAssetRuntimeMember(receiver, memberName, ctx) {
53534
53788
  const record3 = receiver;
@@ -54261,7 +54515,11 @@ function validateClassConstructorDescriptor(info, ctx) {
54261
54515
  }
54262
54516
  let mergedSchema;
54263
54517
  try {
54264
- mergedSchema = mergeInstanceSchema(classId, ctx.vm.classes, ctx.vm.members);
54518
+ mergedSchema = mergeStoredInstanceSchema(
54519
+ classId,
54520
+ ctx.vm.classes,
54521
+ ctx.vm.members
54522
+ );
54265
54523
  } catch (error) {
54266
54524
  throw new NSGetterRuntimeError(
54267
54525
  `Cannot validate constructor for '${schemaClass2.name}': ${error instanceof Error ? error.message : String(error)}`
@@ -54292,6 +54550,16 @@ function validateClassConstructorDescriptor(info, ctx) {
54292
54550
  }
54293
54551
  seenSchemaKeys.add(field.schemaKey);
54294
54552
  seenMemberIds.add(field.memberId);
54553
+ const surfaceEntry = mergeInstanceSchema(
54554
+ classId,
54555
+ ctx.vm.classes,
54556
+ ctx.vm.members
54557
+ ).find((entry) => entry.schemaKey === field.schemaKey);
54558
+ if (surfaceEntry !== void 0 && evalMemberById(ctx.vm, surfaceEntry.memberId)?.isReadOnly === true) {
54559
+ throw new NSGetterRuntimeError(
54560
+ `Constructor field '${field.schemaKey}' on '${schemaClass2.name}' is a read-only declaration member and cannot have an instance value.`
54561
+ );
54562
+ }
54295
54563
  const schemaEntry = schemaByKey.get(field.schemaKey);
54296
54564
  if (schemaEntry === void 0) {
54297
54565
  throw new NSGetterRuntimeError(
@@ -56334,7 +56602,7 @@ function validateCreatedMigrationGraph(args) {
56334
56602
  }
56335
56603
  let merged;
56336
56604
  try {
56337
- merged = mergeInstanceSchema(classId, args.classes, args.members);
56605
+ merged = mergeStoredInstanceSchema(classId, args.classes, args.members);
56338
56606
  } catch (error) {
56339
56607
  throw graphError(
56340
56608
  args,