@neocompose/cli 0.54.1 → 0.56.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
@@ -18769,13 +18769,15 @@ var init_project_schema_contract_generated = __esm({
18769
18769
  "Inherit",
18770
18770
  "Immutable",
18771
18771
  "Save",
18772
- "Session"
18772
+ "Session",
18773
+ "Writable"
18773
18774
  ],
18774
18775
  "NeoAllowedStorage": [
18775
18776
  "Any",
18776
18777
  "Immutable",
18777
18778
  "Save",
18778
- "Session"
18779
+ "Session",
18780
+ "Writable"
18779
18781
  ],
18780
18782
  "NeoListKind": [
18781
18783
  "Ordered",
@@ -22366,9 +22368,9 @@ function contextualAnnotationFields(document, position) {
22366
22368
  }
22367
22369
  const typeAnnotation = findTypeAnnotation(member.type, position);
22368
22370
  if (typeAnnotation) {
22369
- return fieldsForAnnotation(typeAnnotation.name, {
22371
+ return fieldsForAnnotation(typeAnnotation.annotation.name, {
22370
22372
  kind: "type",
22371
- type: semanticType(member.type)
22373
+ type: semanticType(typeAnnotation.type)
22372
22374
  });
22373
22375
  }
22374
22376
  }
@@ -22466,6 +22468,13 @@ function validateDeclaration(uri, declaration, documentKind, environment, diagno
22466
22468
  diagnostics
22467
22469
  );
22468
22470
  if (declaration.kind === "global") {
22471
+ validateTypeAnnotations(
22472
+ uri,
22473
+ declaration.type,
22474
+ "none",
22475
+ environment,
22476
+ diagnostics
22477
+ );
22469
22478
  if (declaration.type.name === "Root") {
22470
22479
  validateProjectRootGlobal(uri, declaration, environment, diagnostics);
22471
22480
  return;
@@ -22507,11 +22516,26 @@ function validateDeclaration(uri, declaration, documentKind, environment, diagno
22507
22516
  validateTypeAnnotations(
22508
22517
  uri,
22509
22518
  parameter4.constraint,
22519
+ "none",
22510
22520
  environment,
22511
22521
  diagnostics
22512
22522
  );
22513
22523
  }
22514
22524
  }
22525
+ for (const parameter4 of declaration.headerParameters ?? []) {
22526
+ validateTypeAnnotations(
22527
+ uri,
22528
+ parameter4.type,
22529
+ "none",
22530
+ environment,
22531
+ diagnostics
22532
+ );
22533
+ }
22534
+ }
22535
+ if (declaration.kind === "class" || declaration.kind === "interface") {
22536
+ for (const baseType of declaration.baseTypes) {
22537
+ validateTypeAnnotations(uri, baseType, "none", environment, diagnostics);
22538
+ }
22515
22539
  }
22516
22540
  const scope = new Map(environment.globals);
22517
22541
  if (declaration.kind === "class") {
@@ -22810,7 +22834,13 @@ function validateMember(uri, member, ownerName, documentKind, ownerScope, enviro
22810
22834
  environment,
22811
22835
  diagnostics
22812
22836
  );
22813
- validateTypeAnnotations(uri, member.type, environment, diagnostics);
22837
+ validateTypeAnnotations(
22838
+ uri,
22839
+ member.type,
22840
+ elementSettingsSite(member, documentKind),
22841
+ environment,
22842
+ diagnostics
22843
+ );
22814
22844
  if (documentKind !== "flow") {
22815
22845
  validateListAnnotations(uri, member, ownerName, environment, diagnostics);
22816
22846
  }
@@ -22818,7 +22848,13 @@ function validateMember(uri, member, ownerName, documentKind, ownerScope, enviro
22818
22848
  if (member.kind === "function") {
22819
22849
  for (const parameter4 of member.parameters) {
22820
22850
  scope.set(parameter4.name, semanticType(parameter4.type));
22821
- validateTypeAnnotations(uri, parameter4.type, environment, diagnostics);
22851
+ validateTypeAnnotations(
22852
+ uri,
22853
+ parameter4.type,
22854
+ "none",
22855
+ environment,
22856
+ diagnostics
22857
+ );
22822
22858
  }
22823
22859
  return;
22824
22860
  }
@@ -22919,16 +22955,77 @@ function validateFlowContent(uri, content, parentScope, environment, diagnostics
22919
22955
  }
22920
22956
  }
22921
22957
  }
22922
- function validateTypeAnnotations(uri, type, environment, diagnostics) {
22923
- validateAnnotations(
22958
+ function elementSettingsSite(member, documentKind) {
22959
+ if (documentKind === "flow" || member.kind !== "field") return "none";
22960
+ const overrides = member.modifiers.includes("override") || member.modifiers.includes("sealed");
22961
+ return overrides ? "override" : "declaringField";
22962
+ }
22963
+ function validateTypeAnnotations(uri, type, site, environment, diagnostics) {
22964
+ rejectTypeAnnotations(
22924
22965
  uri,
22925
- type.annotations,
22926
- { kind: "type", type: semanticType(type) },
22927
- environment,
22966
+ type,
22967
+ "is not valid before a declared type. Annotate the declaration instead.",
22928
22968
  diagnostics
22929
22969
  );
22930
- for (const argument2 of type.typeArguments) {
22931
- validateTypeAnnotations(uri, argument2, environment, diagnostics);
22970
+ validateTypeArgumentAnnotations(uri, type, site, environment, diagnostics);
22971
+ }
22972
+ function validateTypeArgumentAnnotations(uri, type, site, environment, diagnostics) {
22973
+ const elementIndex = collectionElementIndex(type.name);
22974
+ for (const [index, argument2] of type.typeArguments.entries()) {
22975
+ const element = index === elementIndex;
22976
+ if (!element) {
22977
+ rejectTypeAnnotations(
22978
+ uri,
22979
+ argument2,
22980
+ type.name === "Dictionary" ? "is not valid on a Dictionary key. Only the value type accepts element settings." : `is not valid on a ${type.name} type argument. Only a List element or Dictionary value accepts element settings.`,
22981
+ diagnostics
22982
+ );
22983
+ } else if (site === "override") {
22984
+ rejectTypeAnnotations(
22985
+ uri,
22986
+ argument2,
22987
+ "is not valid on an override's element type. Declare element settings on the member that declares the collection.",
22988
+ diagnostics
22989
+ );
22990
+ } else if (site === "none") {
22991
+ rejectTypeAnnotations(
22992
+ uri,
22993
+ argument2,
22994
+ "is not valid here. Only a field's List element or Dictionary value accepts element settings.",
22995
+ diagnostics
22996
+ );
22997
+ } else {
22998
+ validateAnnotations(
22999
+ uri,
23000
+ argument2.annotations,
23001
+ { kind: "type", type: semanticType(argument2) },
23002
+ environment,
23003
+ diagnostics
23004
+ );
23005
+ }
23006
+ validateTypeArgumentAnnotations(
23007
+ uri,
23008
+ argument2,
23009
+ element ? site : "none",
23010
+ environment,
23011
+ diagnostics
23012
+ );
23013
+ }
23014
+ }
23015
+ function collectionElementIndex(name) {
23016
+ if (name === "List") return 0;
23017
+ if (name === "Dictionary") return 1;
23018
+ return null;
23019
+ }
23020
+ function rejectTypeAnnotations(uri, type, reason, diagnostics) {
23021
+ for (const annotation2 of type.annotations) {
23022
+ pushDiagnostic(
23023
+ diagnostics,
23024
+ uri,
23025
+ annotation2.nameRange,
23026
+ "invalid-type-annotation",
23027
+ `@${annotation2.name} ${reason}`
23028
+ );
22932
23029
  }
22933
23030
  }
22934
23031
  function validateAnnotations(uri, annotations, context, environment, diagnostics) {
@@ -22997,6 +23094,7 @@ function fieldsForAnnotation(name, context, environment) {
22997
23094
  return context.kind === "class" ? [{ name: "visibility", type: "NeoClassVisibility" }] : null;
22998
23095
  }
22999
23096
  if (name === "settings") return settingsFields(context);
23097
+ if (context.kind === "type") return null;
23000
23098
  if (name === "storage") return storageFields(context);
23001
23099
  if (name === "distribution") return distributionFields(context);
23002
23100
  if (name === "relations") return relationFields(context, environment);
@@ -23072,7 +23170,7 @@ function settingsFields(context) {
23072
23170
  );
23073
23171
  }
23074
23172
  function distributionFields(context) {
23075
- if (context.kind === "member" || context.kind === "type") {
23173
+ if (context.kind === "member") {
23076
23174
  return [{ name: "kind", type: "NeoSubtreeDistribution" }];
23077
23175
  }
23078
23176
  return null;
@@ -23081,7 +23179,7 @@ function storageFields(context) {
23081
23179
  if (context.kind === "class") {
23082
23180
  return [{ name: "allowed", type: "NeoAllowedStorage" }];
23083
23181
  }
23084
- if (context.kind === "member" || context.kind === "type") {
23182
+ if (context.kind === "member") {
23085
23183
  return [
23086
23184
  { name: "allowed", type: "NeoStorage" },
23087
23185
  { name: "key", type: "string?" }
@@ -24636,13 +24734,13 @@ function annotationEnumOption(annotations, name, field) {
24636
24734
  return match?.[1] ?? null;
24637
24735
  }
24638
24736
  function isListContext(context) {
24639
- return (context.kind === "member" || context.kind === "type") && (context.type.name === "List" || context.type.name === "Set");
24737
+ return context.kind === "member" && (context.type.name === "List" || context.type.name === "Set");
24640
24738
  }
24641
24739
  function findTypeAnnotation(type, position) {
24642
24740
  const own = type.annotations.find(
24643
24741
  (annotation2) => inAnnotationArguments(annotation2, position)
24644
24742
  );
24645
- if (own) return own;
24743
+ if (own) return { annotation: own, type };
24646
24744
  for (const argument2 of type.typeArguments) {
24647
24745
  const nested = findTypeAnnotation(argument2, position);
24648
24746
  if (nested) return nested;
@@ -31446,10 +31544,12 @@ function flowArguments(argumentsValue) {
31446
31544
  }));
31447
31545
  }
31448
31546
  function manifestType(type) {
31547
+ const annotations = manifestAnnotations(type.annotations);
31449
31548
  return {
31450
31549
  name: type.name,
31451
31550
  nullable: type.nullable,
31452
- arguments: type.typeArguments.map(manifestType)
31551
+ arguments: type.typeArguments.map(manifestType),
31552
+ ...annotations.length === 0 ? {} : { annotations }
31453
31553
  };
31454
31554
  }
31455
31555
  function manifestAnnotations(annotations) {
@@ -31979,7 +32079,12 @@ function assertFlowArguments(value, path) {
31979
32079
  }
31980
32080
  function assertType(value, path) {
31981
32081
  const type = record(value, path);
31982
- exactKeys(type, path, ["name", "nullable", "arguments"]);
32082
+ exactKeysWithOptional(
32083
+ type,
32084
+ path,
32085
+ ["name", "nullable", "arguments"],
32086
+ ["annotations"]
32087
+ );
31983
32088
  string(type.name, `${path}.name`);
31984
32089
  if (typeof type.nullable !== "boolean") {
31985
32090
  throw new Error(`${path}.nullable must be boolean.`);
@@ -31987,6 +32092,10 @@ function assertType(value, path) {
31987
32092
  array(type.arguments, `${path}.arguments`).forEach(
31988
32093
  (argument2, index) => assertType(argument2, `${path}.arguments[${index}]`)
31989
32094
  );
32095
+ if (type.annotations === void 0) return;
32096
+ array(type.annotations, `${path}.annotations`).forEach(
32097
+ (entry, index) => assertAnnotation(entry, `${path}.annotations[${index}]`)
32098
+ );
31990
32099
  }
31991
32100
  function assertAnnotation(value, path) {
31992
32101
  const annotation2 = record(value, path);
@@ -32350,10 +32459,22 @@ function resolvedAllowedStorage(classId, environment) {
32350
32459
  }
32351
32460
  return null;
32352
32461
  }
32353
- function staticDefaultWritability(classId, environment) {
32354
- const allowed = resolvedAllowedStorage(classId, environment);
32462
+ function constraintDefaultWritability(allowed) {
32355
32463
  return allowed === "immutable" || allowed === "save" || allowed === "session" ? allowed : "session";
32356
32464
  }
32465
+ function declaredStorageWritability(storage, staticOwnerClassId, environment) {
32466
+ if (storage === "immutable" || storage === "save" || storage === "session") {
32467
+ return storage;
32468
+ }
32469
+ if (storage === "writable") return "runtime";
32470
+ if (!staticOwnerClassId) return void 0;
32471
+ return staticDefaultWritability(staticOwnerClassId, environment);
32472
+ }
32473
+ function staticDefaultWritability(classId, environment) {
32474
+ return constraintDefaultWritability(
32475
+ resolvedAllowedStorage(classId, environment)
32476
+ );
32477
+ }
32357
32478
  function createRootType(ids, environment) {
32358
32479
  const definitions = [
32359
32480
  ["Assets", ids.assets, false],
@@ -32415,7 +32536,7 @@ function effectiveMemberWritability(members, classes, roots) {
32415
32536
  seen.add(memberId);
32416
32537
  const member = memberById2.get(memberId);
32417
32538
  if (!member) return null;
32418
- if (member.storage === "immutable" || member.storage === "save" || member.storage === "session") {
32539
+ if (member.storage === "immutable" || member.storage === "save" || member.storage === "session" || member.storage === "writable") {
32419
32540
  return member.storage;
32420
32541
  }
32421
32542
  return typeof member.overrideOf === "string" ? declaredStorage(member.overrideOf, seen) : null;
@@ -32438,8 +32559,8 @@ function effectiveMemberWritability(members, classes, roots) {
32438
32559
  seen.add(currentId);
32439
32560
  const current = classById.get(currentId);
32440
32561
  if (!current) break;
32441
- if (current.allowedStorage === "immutable" || current.allowedStorage === "save" || current.allowedStorage === "session") {
32442
- return current.allowedStorage;
32562
+ if (typeof current.allowedStorage === "string") {
32563
+ return constraintDefaultWritability(current.allowedStorage);
32443
32564
  }
32444
32565
  currentId = typeof current.extendsClassId === "string" ? current.extendsClassId : null;
32445
32566
  }
@@ -32474,6 +32595,7 @@ function effectiveMemberWritability(members, classes, roots) {
32474
32595
  }
32475
32596
  const effective = /* @__PURE__ */ new Map();
32476
32597
  const anchored = /* @__PURE__ */ new Set();
32598
+ const writable = /* @__PURE__ */ new Set();
32477
32599
  const rootStorage = /* @__PURE__ */ new Map();
32478
32600
  if (typeof roots.assets === "string") {
32479
32601
  rootStorage.set(roots.assets, "immutable");
@@ -32483,16 +32605,19 @@ function effectiveMemberWritability(members, classes, roots) {
32483
32605
  rootStorage.set(roots.session, "session");
32484
32606
  }
32485
32607
  for (const [memberId, member] of memberById2) {
32486
- const root = rootStorage.get(memberId);
32487
- const declared = declaredStorage(memberId);
32488
- let storage = root ?? declared;
32489
- if (storage === void 0 || storage === null) {
32608
+ const declared = rootStorage.get(memberId) ?? declaredStorage(memberId);
32609
+ if (declared === "writable") {
32610
+ writable.add(memberId);
32611
+ continue;
32612
+ }
32613
+ let storage = declared;
32614
+ if (storage === null) {
32490
32615
  const owner = optionalRecord(member.owner);
32491
32616
  if (member.modifier === "static" && owner?.kind === "classMember" && typeof owner.classId === "string") {
32492
32617
  storage = staticDefault(owner.classId);
32493
32618
  }
32494
32619
  }
32495
- if (storage === void 0 || storage === null) continue;
32620
+ if (storage === null) continue;
32496
32621
  effective.set(memberId, /* @__PURE__ */ new Set([storage]));
32497
32622
  anchored.add(memberId);
32498
32623
  }
@@ -32502,8 +32627,11 @@ function effectiveMemberWritability(members, classes, roots) {
32502
32627
  for (const memberId of memberById2.keys()) {
32503
32628
  if (anchored.has(memberId)) continue;
32504
32629
  const next = new Set(effective.get(memberId) ?? []);
32630
+ const isWritable = writable.has(memberId);
32505
32631
  for (const parentId of parents.get(memberId) ?? []) {
32506
- for (const storage of effective.get(parentId) ?? []) next.add(storage);
32632
+ for (const storage of effective.get(parentId) ?? []) {
32633
+ next.add(isWritable && storage === "immutable" ? "session" : storage);
32634
+ }
32507
32635
  }
32508
32636
  const current = effective.get(memberId);
32509
32637
  if (current?.size === next.size || next.size === 0) continue;
@@ -32634,7 +32762,16 @@ function memberSymbol(member, schemaKey, environment, field) {
32634
32762
  }
32635
32763
  const writable = isReadOnly ? false : kind === "computed" ? computedHasSetter(member, field) : true;
32636
32764
  const storage = typeof member.storage === "string" ? member.storage : void 0;
32637
- const writability = isReadOnly ? "readOnly" : kind === "computed" ? writable ? "setter" : "readOnly" : !writable ? "readOnly" : storage === "immutable" || storage === "save" || storage === "session" ? storage : isStatic && ownerClassId ? staticDefaultWritability(ownerClassId, environment) : void 0;
32765
+ let writability;
32766
+ if (!writable) writability = "readOnly";
32767
+ else if (kind === "computed") writability = "setter";
32768
+ else {
32769
+ writability = declaredStorageWritability(
32770
+ storage,
32771
+ isStatic ? ownerClassId : void 0,
32772
+ environment
32773
+ );
32774
+ }
32638
32775
  const lookupCollectionMemberId = kind === "lookup" ? string2(member.collectionMemberId, `${field}.collectionMemberId`) : null;
32639
32776
  const lookupCollectionWritability = lookupCollectionMemberId === null ? void 0 : environment.effectiveWritabilityByMemberId.get(
32640
32777
  lookupCollectionMemberId
@@ -39996,7 +40133,13 @@ var init_codecs = __esm({
39996
40133
  };
39997
40134
  MEMBER_MODIFIERS = ["virtual", "sealed", "abstract", "static"];
39998
40135
  MEMBER_ACCESS = ["public", "protected", "private"];
39999
- MEMBER_STORAGE = ["inherit", "immutable", "save", "session"];
40136
+ MEMBER_STORAGE = [
40137
+ "inherit",
40138
+ "immutable",
40139
+ "save",
40140
+ "session",
40141
+ "writable"
40142
+ ];
40000
40143
  MEMBER_DISTRIBUTION = ["sparse", "packed"];
40001
40144
  STRING_FORMAT = ["localized", "plain"];
40002
40145
  MEMBER_SEARCH_BY = ["none", "memberKey"];
@@ -40716,7 +40859,7 @@ function schemaClassToDocument(schemaClass2) {
40716
40859
  uiVisibility: schemaClass2.hiddenInMemberSelector ? 1 : void 0,
40717
40860
  modifier: schemaClass2.declarationModifier === "abstract" ? 1 : schemaClass2.declarationModifier === "sealed" ? 2 : void 0,
40718
40861
  system: systemToDocument(schemaClass2.system),
40719
- allowedStorage: schemaClass2.allowedStorage === null ? void 0 : ["immutable", "save", "session"].indexOf(schemaClass2.allowedStorage) + 1,
40862
+ allowedStorage: schemaClass2.allowedStorage === null ? void 0 : CLASS_ALLOWED_STORAGE.indexOf(schemaClass2.allowedStorage),
40720
40863
  allowedStorageKeys: schemaClass2.allowedStorageKeys,
40721
40864
  // An unconstrained param is stored with no `constraint` key. The manifest
40722
40865
  // spells that absence `null` for a uniform in-memory shape, so emitting
@@ -40739,7 +40882,7 @@ function schemaClassToDocument(schemaClass2) {
40739
40882
  function allowedStorageFromDocument(value, record6) {
40740
40883
  const storage = ordinalValue(
40741
40884
  value ?? 0,
40742
- ["any", "immutable", "save", "session"],
40885
+ CLASS_ALLOWED_STORAGE,
40743
40886
  record6,
40744
40887
  "allowedStorage"
40745
40888
  );
@@ -40786,12 +40929,19 @@ function optionalDocsTextProperty(value, record6) {
40786
40929
  const docsText = optionalDocsText(value, record6, "docsText");
40787
40930
  return docsText === void 0 ? {} : { docsText };
40788
40931
  }
40789
- var CLASS_SCHEMA_RECORD_ADAPTER;
40932
+ var CLASS_ALLOWED_STORAGE, CLASS_SCHEMA_RECORD_ADAPTER;
40790
40933
  var init_class = __esm({
40791
40934
  "src/project-manifest/record-adapters/class.ts"() {
40792
40935
  "use strict";
40793
40936
  init_contracts();
40794
40937
  init_codecs();
40938
+ CLASS_ALLOWED_STORAGE = [
40939
+ "any",
40940
+ "immutable",
40941
+ "save",
40942
+ "session",
40943
+ "writable"
40944
+ ];
40795
40945
  CLASS_SCHEMA_RECORD_ADAPTER = {
40796
40946
  recordKind: "class",
40797
40947
  manifestCollection: "classes",
@@ -42892,7 +43042,7 @@ var init_schema_member = __esm({
42892
43042
  defaultValue: nullable(schemaDefaultValueSchema),
42893
43043
  overrideOf: nullableId2,
42894
43044
  system: nullable(schemaSystemMetadataSchema),
42895
- storage: nullable(picklist(["immutable", "save", "session"])),
43045
+ storage: nullable(picklist(["immutable", "save", "session", "writable"])),
42896
43046
  distribution: nullable(picklist(["sparse", "packed"])),
42897
43047
  storageKey: nullableId2
42898
43048
  };
@@ -44558,7 +44708,7 @@ function booleanAt(value, path) {
44558
44708
  }
44559
44709
  function nullableStorage(value, path) {
44560
44710
  if (value === null) return;
44561
- stringIn(value, /* @__PURE__ */ new Set(["immutable", "save", "session"]), path);
44711
+ stringIn(value, /* @__PURE__ */ new Set(["immutable", "save", "session", "writable"]), path);
44562
44712
  }
44563
44713
  function stringIn(value, allowed, path) {
44564
44714
  const result = stringAt(value, path);
@@ -45327,15 +45477,59 @@ var init_class_generics = __esm({
45327
45477
 
45328
45478
  // ../src/models/members/member-storage.ts
45329
45479
  function isMemberStorageKind(value) {
45330
- return value === 0 /* Inherit */ || value === 1 /* Immutable */ || value === 2 /* Save */ || value === 3 /* Session */;
45480
+ return value === 0 /* Inherit */ || value === 1 /* Immutable */ || value === 2 /* Save */ || value === 3 /* Session */ || value === 4 /* Writable */;
45331
45481
  }
45332
45482
  function isEffectiveMemberStorage(value) {
45483
+ return value === 1 /* Immutable */ || value === 2 /* Save */ || value === 3 /* Session */;
45484
+ }
45485
+ function isClassAllowedStorage(value) {
45333
45486
  if (!isMemberStorageKind(value)) return false;
45334
45487
  return value !== 0 /* Inherit */;
45335
45488
  }
45489
+ function childEffectiveStorage(declared, parent) {
45490
+ switch (declared) {
45491
+ case 0 /* Inherit */:
45492
+ return parent;
45493
+ case 4 /* Writable */:
45494
+ return parent === 2 /* Save */ ? 2 /* Save */ : 3 /* Session */;
45495
+ default:
45496
+ return declared;
45497
+ }
45498
+ }
45499
+ function constraintDefaultStorage(constraint) {
45500
+ if (constraint === null) return 3 /* Session */;
45501
+ if (constraint === 4 /* Writable */) {
45502
+ return 3 /* Session */;
45503
+ }
45504
+ return constraint;
45505
+ }
45506
+ function createWritableAncestorLookup(memberById2) {
45507
+ const memo = /* @__PURE__ */ new Map();
45508
+ const lookup = (member) => {
45509
+ const cached = memo.get(member.id);
45510
+ if (cached !== void 0) return cached;
45511
+ memo.set(member.id, null);
45512
+ const baseId = member.extendsMemberId;
45513
+ const base = baseId === void 0 ? void 0 : memberById2(baseId);
45514
+ if (base === void 0) return null;
45515
+ const result = base.storage === 4 /* Writable */ ? base : lookup(base);
45516
+ memo.set(member.id, result);
45517
+ return result;
45518
+ };
45519
+ return lookup;
45520
+ }
45521
+ var MemberStorageKind;
45336
45522
  var init_member_storage = __esm({
45337
45523
  "../src/models/members/member-storage.ts"() {
45338
45524
  "use strict";
45525
+ MemberStorageKind = /* @__PURE__ */ ((MemberStorageKind3) => {
45526
+ MemberStorageKind3[MemberStorageKind3["Inherit"] = 0] = "Inherit";
45527
+ MemberStorageKind3[MemberStorageKind3["Immutable"] = 1] = "Immutable";
45528
+ MemberStorageKind3[MemberStorageKind3["Save"] = 2] = "Save";
45529
+ MemberStorageKind3[MemberStorageKind3["Session"] = 3] = "Session";
45530
+ MemberStorageKind3[MemberStorageKind3["Writable"] = 4] = "Writable";
45531
+ return MemberStorageKind3;
45532
+ })(MemberStorageKind || {});
45339
45533
  }
45340
45534
  });
45341
45535
 
@@ -47312,7 +47506,7 @@ function isNeoSchemaClassBase(value) {
47312
47506
  const v = value;
47313
47507
  return typeof v?.name === "string" && isValidDocsText(v.docsText) && isClassSchema(v?.schema) && isOptionalSchemaKeyOrder(v?.schemaKeyOrder) && (v.implementsInterfaceIds === void 0 || Array.isArray(v.implementsInterfaceIds) && v.implementsInterfaceIds.every(
47314
47508
  (interfaceId) => typeof interfaceId === "string" && interfaceId.length > 0
47315
- )) && (v.uiVisibility === void 0 || v.uiVisibility === 0 /* Visible */ || v.uiVisibility === 1 /* Hidden */) && (v.modifier === void 0 || v.modifier === 0 /* Open */ || v.modifier === 1 /* Abstract */ || v.modifier === 2 /* Sealed */) && (v.allowedStorage === void 0 || isEffectiveMemberStorage(v.allowedStorage)) && (v.allowedStorageKeys === void 0 || Array.isArray(v.allowedStorageKeys) && v.allowedStorageKeys.every((key) => typeof key === "string")) && (v.genericParams === void 0 || Array.isArray(v.genericParams) && v.genericParams.every(isGenericParamDeclaration)) && (v.extendsGenericBindings === void 0 || isGenericBindingsRecord(v.extendsGenericBindings)) && (v.constructorIds === void 0 || Array.isArray(v.constructorIds) && v.constructorIds.every(
47509
+ )) && (v.uiVisibility === void 0 || v.uiVisibility === 0 /* Visible */ || v.uiVisibility === 1 /* Hidden */) && (v.modifier === void 0 || v.modifier === 0 /* Open */ || v.modifier === 1 /* Abstract */ || v.modifier === 2 /* Sealed */) && (v.allowedStorage === void 0 || isClassAllowedStorage(v.allowedStorage)) && (v.allowedStorageKeys === void 0 || Array.isArray(v.allowedStorageKeys) && v.allowedStorageKeys.every((key) => typeof key === "string")) && (v.genericParams === void 0 || Array.isArray(v.genericParams) && v.genericParams.every(isGenericParamDeclaration)) && (v.extendsGenericBindings === void 0 || isGenericBindingsRecord(v.extendsGenericBindings)) && (v.constructorIds === void 0 || Array.isArray(v.constructorIds) && v.constructorIds.every(
47316
47510
  (constructorId) => typeof constructorId === "string" && constructorId.length > 0
47317
47511
  ) && new Set(v.constructorIds).size === v.constructorIds.length) && (v.requiredConstructorId === void 0 || typeof v.requiredConstructorId === "string" && v.requiredConstructorId.length > 0 && (v.constructorIds ?? []).length === 0) && (v.targetMemberId === void 0 || typeof v.targetMemberId === "string" && v.targetMemberId.length > 0) && (v.system === void 0 || isSystemMetadata(v.system));
47318
47512
  }
@@ -52913,7 +53107,7 @@ function assertOwnedSchemaIsImmutable(args) {
52913
53107
  const bindingKey = `${args.memberId}\0${genericEnvironmentKey(args.genericEnv)}`;
52914
53108
  if (args.visitedBindings.has(bindingKey)) return;
52915
53109
  args.visitedBindings.add(bindingKey);
52916
- if (resolved.storage === 2 /* Save */ || resolved.storage === 3 /* Session */) {
53110
+ if (resolved.storage === 2 /* Save */ || resolved.storage === 3 /* Session */ || resolved.storage === 4 /* Writable */) {
52917
53111
  throw new Error(
52918
53112
  `Read-only member "${args.label}" has a non-Immutable owned default child "${resolved.name}"; ${args.ownerContext}.`
52919
53113
  );
@@ -56804,6 +56998,9 @@ var init_effective_storage = __esm({
56804
56998
  schemaIndex;
56805
56999
  parentIdsByMemberId = /* @__PURE__ */ new Map();
56806
57000
  effectiveByMemberId = /* @__PURE__ */ new Map();
57001
+ writableAncestor = createWritableAncestorLookup(
57002
+ (id2) => this.schemaIndex.member(id2)
57003
+ );
56807
57004
  resolving = /* @__PURE__ */ new Set();
56808
57005
  /** Declared storage of `memberId`, resolved through the extends chain. */
56809
57006
  declaredStorage(memberId) {
@@ -56812,6 +57009,15 @@ var init_effective_storage = __esm({
56812
57009
  this.schemaIndex.membersById
56813
57010
  );
56814
57011
  }
57012
+ /**
57013
+ * Nearest member in `memberId`'s `extendsMemberId` chain, excluding itself,
57014
+ * whose own record declares `Writable` (P93 §1.4), or null.
57015
+ */
57016
+ writableAncestorId(memberId) {
57017
+ const member = this.schemaIndex.member(memberId);
57018
+ if (member === void 0) return null;
57019
+ return this.writableAncestor(member)?.id ?? null;
57020
+ }
56815
57021
  /** Placement-parent member ids of `memberId` (empty for roots). */
56816
57022
  parentMemberIds(memberId) {
56817
57023
  if (this.ctx.rootStorage.has(memberId)) return [];
@@ -56835,21 +57041,21 @@ var init_effective_storage = __esm({
56835
57041
  result.add(rootStorage);
56836
57042
  } else {
56837
57043
  const declared = this.declaredStorage(memberId);
56838
- const member = this.schemaIndex.member(memberId);
56839
- if (isStaticMember(member) === true) {
56840
- if (declared !== 0 /* Inherit */) {
56841
- result.add(declared);
56842
- } else {
56843
- const declaringClassId = this.schemaIndex.firstSchemaPlacement(memberId)?.ownerClass.id;
56844
- const inherited = declaringClassId === void 0 ? null : resolveAllowedStorage(declaringClassId, this.ctx.classes);
56845
- result.add(inherited ?? 3 /* Session */);
56846
- }
56847
- } else if (declared !== 0 /* Inherit */) {
57044
+ if (isEffectiveMemberStorage(declared)) {
56848
57045
  result.add(declared);
57046
+ } else if (isStaticMember(this.schemaIndex.member(memberId))) {
57047
+ const declaringClassId = this.schemaIndex.firstSchemaPlacement(memberId)?.ownerClass.id;
57048
+ const constraint = declaringClassId === void 0 ? null : resolveAllowedStorage(declaringClassId, this.ctx.classes);
57049
+ result.add(
57050
+ childEffectiveStorage(
57051
+ declared,
57052
+ constraintDefaultStorage(constraint)
57053
+ )
57054
+ );
56849
57055
  } else {
56850
57056
  for (const parentId of this.parentMemberIds(memberId)) {
56851
57057
  for (const storage of this.effectiveStorages(parentId)) {
56852
- result.add(storage);
57058
+ result.add(childEffectiveStorage(declared, storage));
56853
57059
  }
56854
57060
  }
56855
57061
  }
@@ -56864,26 +57070,44 @@ var init_effective_storage = __esm({
56864
57070
  * Effective storage for one concrete placement chain, ordered root-first
56865
57071
  * (the project root at index 0, the target member last). Used when the
56866
57072
  * caller knows the exact path (NeoScript member walks, value trees).
57073
+ * Anchors at the root, the nearest concrete declaration, or a single-storage
57074
+ * static head, then folds the members below through `childEffectiveStorage`.
56867
57075
  */
56868
57076
  effectiveStorageForPath(memberIdsRootToLeaf) {
56869
- for (let i = memberIdsRootToLeaf.length - 1; i >= 0; i--) {
56870
- const memberId = memberIdsRootToLeaf[i];
56871
- const rootStorage = this.ctx.rootStorage.get(memberId);
56872
- if (rootStorage !== void 0 && i === 0) return rootStorage;
57077
+ let anchorIndex = memberIdsRootToLeaf.length - 1;
57078
+ let storage;
57079
+ for (; anchorIndex >= 0; anchorIndex--) {
57080
+ const memberId = memberIdsRootToLeaf[anchorIndex];
57081
+ if (anchorIndex === 0) storage = this.ctx.rootStorage.get(memberId);
57082
+ if (storage !== void 0) break;
56873
57083
  const declared = this.declaredStorage(memberId);
56874
- if (declared !== 0 /* Inherit */) return declared;
57084
+ if (isEffectiveMemberStorage(declared)) {
57085
+ storage = declared;
57086
+ break;
57087
+ }
57088
+ }
57089
+ if (storage === void 0) {
57090
+ anchorIndex = 0;
57091
+ storage = this.staticRootStorage(memberIdsRootToLeaf[0]);
56875
57092
  }
56876
- const rootId = memberIdsRootToLeaf[0];
56877
- const anchored = rootId === void 0 ? void 0 : this.ctx.rootStorage.get(rootId);
56878
- if (anchored !== void 0) return anchored;
57093
+ for (let i = anchorIndex + 1; i < memberIdsRootToLeaf.length; i++) {
57094
+ storage = childEffectiveStorage(
57095
+ this.declaredStorage(memberIdsRootToLeaf[i]),
57096
+ storage
57097
+ );
57098
+ }
57099
+ return storage;
57100
+ }
57101
+ /** A static chain head's storage when it resolves to exactly one. */
57102
+ staticRootStorage(rootId) {
56879
57103
  if (rootId !== void 0 && isStaticMember(this.schemaIndex.member(rootId))) {
56880
57104
  const staticStorages = this.effectiveStorages(rootId);
56881
57105
  if (staticStorages.size === 1) {
56882
- return staticStorages.values().next().value;
57106
+ for (const storage of staticStorages) return storage;
56883
57107
  }
56884
57108
  }
56885
57109
  throw new Error(
56886
- `Storage path did not resolve: no member in the chain declares a storage class and the chain head "${rootId ?? "(empty)"}" is not a stamped project root.`
57110
+ `Storage path did not resolve: no member in the chain declares an Immutable, Save, or Session storage class and the chain head "${rootId ?? "(empty)"}" is not a stamped project root.`
56887
57111
  );
56888
57112
  }
56889
57113
  /** Class's merged (inheritance-resolved) schema. */
@@ -58134,7 +58358,12 @@ ${signature} => ${expression};`;
58134
58358
  context.formAlternates.push({ shorthand, block });
58135
58359
  return shorthand;
58136
58360
  }
58137
- const type = renderMemberType(context, member, enclosingClassId);
58361
+ const type = renderMemberType(
58362
+ context,
58363
+ member,
58364
+ enclosingClassId,
58365
+ member.overrideOf === null
58366
+ );
58138
58367
  const initializer = initDefaultSource(member) ?? (member.modifier === "static" ? context.staticInitializers.get(member.id) : void 0) ?? context.defaultInitializers.get(member.id) ?? renderDefault(context, member, enclosingClassId);
58139
58368
  return `${annotations.join("\n")}
58140
58369
  ${prefix}${type} ${member.name}${initializer === null ? ";" : ` = ${initializer};`}`;
@@ -58271,7 +58500,18 @@ function listAnnotations(member) {
58271
58500
  })
58272
58501
  ];
58273
58502
  }
58274
- function renderMemberType(context, member, enclosingClassId) {
58503
+ function renderEntryType(context, entryMemberId, label, enclosingClassId, elementSettings) {
58504
+ const entry = required(context.members, entryMemberId, label);
58505
+ const type = renderMemberType(
58506
+ context,
58507
+ entry,
58508
+ enclosingClassId,
58509
+ elementSettings
58510
+ );
58511
+ const settings = elementSettings ? memberSettings(context, entry) : [];
58512
+ return settings.length === 0 ? type : `${settings.join(" ")} ${type}`;
58513
+ }
58514
+ function renderMemberType(context, member, enclosingClassId, elementSettings = false) {
58275
58515
  const nullable2 = !member.required;
58276
58516
  const closedGenerics = enclosingClassId === void 0 ? void 0 : classGenericMemberBindings(context.classes, enclosingClassId);
58277
58517
  let value;
@@ -58362,11 +58602,11 @@ function renderMemberType(context, member, enclosingClassId) {
58362
58602
  break;
58363
58603
  }
58364
58604
  case "list":
58365
- value = `List<${renderMemberType(context, required(context.members, member.entryMemberId, "list entry"), enclosingClassId)}>`;
58605
+ value = `List<${renderEntryType(context, member.entryMemberId, "list entry", enclosingClassId, elementSettings)}>`;
58366
58606
  break;
58367
58607
  case "dictionary": {
58368
58608
  const key = member.key.kind === "string" ? "string" : required(context.enums, member.key.enumId, "dictionary key enum").name;
58369
- value = `Dictionary<${key}, ${renderMemberType(context, required(context.members, member.entryMemberId, "dictionary entry"), enclosingClassId)}>`;
58609
+ value = `Dictionary<${key}, ${renderEntryType(context, member.entryMemberId, "dictionary entry", enclosingClassId, elementSettings)}>`;
58370
58610
  break;
58371
58611
  }
58372
58612
  case "lookup": {
@@ -64088,6 +64328,14 @@ function buildRootStorageMap(project) {
64088
64328
  }
64089
64329
  return map;
64090
64330
  }
64331
+ function writtenRootStorage(project, memberIds) {
64332
+ const map = /* @__PURE__ */ new Map();
64333
+ for (const root of PROJECT_ROOTS) {
64334
+ const memberId = project[root.projectField];
64335
+ if (memberIds.has(memberId)) map.set(memberId, root.storage);
64336
+ }
64337
+ return map;
64338
+ }
64091
64339
  function isProjectRootMember(project, memberId) {
64092
64340
  return PROJECT_ROOTS.some((root) => project[root.projectField] === memberId);
64093
64341
  }
@@ -64679,7 +64927,9 @@ function symbolWritability(memberId, context, staticOwnerClassId) {
64679
64927
  if (storage === 0 /* Inherit */ && staticOwnerClassId === null) {
64680
64928
  return {};
64681
64929
  }
64682
- const effectiveStorage = storage === 0 /* Inherit */ ? resolveAllowedStorage(staticOwnerClassId, context.vm.classes) ?? 3 /* Session */ : storage;
64930
+ const effectiveStorage = storage === 0 /* Inherit */ ? constraintDefaultStorage(
64931
+ resolveAllowedStorage(staticOwnerClassId, context.vm.classes)
64932
+ ) : storage;
64683
64933
  switch (effectiveStorage) {
64684
64934
  case 1 /* Immutable */:
64685
64935
  return { writability: "immutable" };
@@ -64687,6 +64937,8 @@ function symbolWritability(memberId, context, staticOwnerClassId) {
64687
64937
  return { writability: "save" };
64688
64938
  case 3 /* Session */:
64689
64939
  return { writability: "session" };
64940
+ case 4 /* Writable */:
64941
+ return { writability: "runtime" };
64690
64942
  }
64691
64943
  }
64692
64944
  function uniqueEffectiveWritability(memberId, context) {
@@ -90556,6 +90808,68 @@ function resolveLocalizableStringWriteOwners(document, changes, requestedValueId
90556
90808
  }
90557
90809
  return owners;
90558
90810
  }
90811
+ function packedLocalizationConversionChanges(args) {
90812
+ const beforeById = new Map(
90813
+ args.beforeMembers.map((member) => [member.id, member])
90814
+ );
90815
+ const becameLocalized = (member) => {
90816
+ if (!isMemberStringBase(member)) return false;
90817
+ if (!isLocalizedStringMember(member)) return false;
90818
+ const id2 = getOptionalString(member, "id");
90819
+ const before = id2 === void 0 ? void 0 : beforeById.get(id2);
90820
+ if (before === void 0) return false;
90821
+ const resolved = resolveMember2(before, args.beforeMembers);
90822
+ return isMemberStringBase(resolved) && !isLocalizedStringMember(resolved);
90823
+ };
90824
+ const postMembers = new Map(
90825
+ args.postDocument.members.map((member) => [member.id, member])
90826
+ );
90827
+ const flips = args.changes.some((change) => {
90828
+ if (change.recordKind !== "member" || change.operation === "delete") {
90829
+ return false;
90830
+ }
90831
+ const member = postMembers.get(change.recordId);
90832
+ return member !== void 0 && becameLocalized(resolveMember2(member, args.postDocument.members));
90833
+ });
90834
+ if (!flips) return [];
90835
+ const changedValueIds = new Set(
90836
+ args.changes.flatMap(
90837
+ (change) => change.recordKind === "value" ? [change.recordId] : []
90838
+ )
90839
+ );
90840
+ const omitted = /* @__PURE__ */ new Map();
90841
+ for (const change of args.submitted) {
90842
+ if (change.recordKind !== "value" || change.operation === "delete") {
90843
+ continue;
90844
+ }
90845
+ if (!isMemberValue(change.nextData)) continue;
90846
+ for (const child of decodePackedValueRow(change.nextData).children) {
90847
+ if (changedValueIds.has(child.id)) continue;
90848
+ if (typeof child.value !== "string" || child.value === "") continue;
90849
+ omitted.set(child.id, { child, intent: change.intent });
90850
+ }
90851
+ }
90852
+ if (omitted.size === 0) return [];
90853
+ const owners = resolveLocalizableStringWriteOwners(
90854
+ args.postDocument,
90855
+ args.changes,
90856
+ new Set(omitted.keys())
90857
+ );
90858
+ const conversions = [];
90859
+ for (const [valueId, { child, intent }] of omitted) {
90860
+ const owner = owners.get(valueId);
90861
+ if (owner === void 0 || !becameLocalized(owner)) continue;
90862
+ conversions.push({
90863
+ intent,
90864
+ recordKind: "value",
90865
+ recordId: valueId,
90866
+ operation: "update",
90867
+ deleted: false,
90868
+ nextData: child
90869
+ });
90870
+ }
90871
+ return conversions;
90872
+ }
90559
90873
  function reconcileMemberTextUsage(document, changes, before, referencedOutsideDocument, now, contentHashByKey) {
90560
90874
  const assignmentChanges = changes.filter(
90561
90875
  (change) => change.recordKind === "member" || change.recordKind === "value"
@@ -90828,6 +91142,7 @@ var init_localizable_member_value_writes = __esm({
90828
91142
  init_project_record_live_references();
90829
91143
  init_localization2();
90830
91144
  init_members();
91145
+ init_packed_value_encoding();
90831
91146
  init_variant_value_graph();
90832
91147
  init_project_version_intents();
90833
91148
  init_constructor_argument_ownership();
@@ -91219,10 +91534,11 @@ function commitPreparationMemberDefaultValueScope(args) {
91219
91534
  return { exactValueIds, descendantValueIds, evaluatesSource };
91220
91535
  }
91221
91536
  function planCommitPreparationInitialScope(args) {
91537
+ const submitted = args.changes;
91222
91538
  args = {
91223
91539
  ...args,
91224
91540
  changes: expandPackedValueWriteChanges({
91225
- changes: args.changes,
91541
+ changes: submitted,
91226
91542
  baseValues: args.document.values ?? [],
91227
91543
  basePhysicalValues: args.document.physicalValues,
91228
91544
  omitUnchangedChildren: true
@@ -91233,6 +91549,18 @@ function planCommitPreparationInitialScope(args) {
91233
91549
  );
91234
91550
  const currentDocument = overlayPlanningDocument(args.document, []);
91235
91551
  const postDocument = overlayPlanningDocument(currentDocument, args.changes);
91552
+ args = {
91553
+ ...args,
91554
+ changes: [
91555
+ ...args.changes,
91556
+ ...packedLocalizationConversionChanges({
91557
+ submitted,
91558
+ changes: args.changes,
91559
+ beforeMembers: currentDocument.members,
91560
+ postDocument
91561
+ })
91562
+ ]
91563
+ };
91236
91564
  const exactRecords = /* @__PURE__ */ new Map();
91237
91565
  const descendantRecords = /* @__PURE__ */ new Map();
91238
91566
  const rememberExact = (recordKind, recordId, includeDescendants = false) => {
@@ -91722,8 +92050,13 @@ function planCommitPreparationLoadedClosureScope(args) {
91722
92050
  postings.set(commitPreparationPostingRequestKey(posting), posting);
91723
92051
  };
91724
92052
  for (const record6 of args.records) {
91725
- if (record6.recordKind === "value" && isMemberValue(record6.data) && typeof record6.data.value === "string" && record6.data.value !== "") {
91726
- rememberExact("localized-text", record6.data.value);
92053
+ if (record6.recordKind === "value" && isMemberValue(record6.data)) {
92054
+ const decoded = decodePackedValueRow(record6.data);
92055
+ for (const row of [decoded.row, ...decoded.children]) {
92056
+ if (typeof row.value === "string" && row.value !== "") {
92057
+ rememberExact("localized-text", row.value);
92058
+ }
92059
+ }
91727
92060
  }
91728
92061
  if (record6.recordKind === "member" && isMemberStringBase(record6.data) && isLocalizedStringMember(record6.data) && typeof record6.data.defaultValue?.value === "string" && record6.data.defaultValue.value !== "") {
91729
92062
  rememberExact("localized-text", record6.data.defaultValue.value);
@@ -97069,6 +97402,14 @@ function* prepareServerOwnedSchemaCommitPasses(args) {
97069
97402
  true
97070
97403
  );
97071
97404
  authoredChanges = retargeted;
97405
+ authoredChanges.push(
97406
+ ...packedLocalizationConversionChanges({
97407
+ submitted: args.changes,
97408
+ changes: authoredChanges,
97409
+ beforeMembers: args.document.members,
97410
+ postDocument: authoredPost
97411
+ })
97412
+ );
97072
97413
  const editedValueIds = new Set(
97073
97414
  authoredChanges.filter(
97074
97415
  (change) => change.recordKind === "value" && change.operation === "update"
@@ -101163,10 +101504,6 @@ var init_unity_static_members = __esm({
101163
101504
  });
101164
101505
 
101165
101506
  // ../src/models/animation/animation-clips.ts
101166
- function isWorldAnimationStructuralMember(memberId, members) {
101167
- const membersById = new Map(members.map((member) => [member.id, member]));
101168
- return isWorldAnimationStructuralMemberFromIndex(memberId, membersById);
101169
- }
101170
101507
  function isWorldAnimationStructuralMemberFromIndex(memberId, membersById) {
101171
101508
  const visited = /* @__PURE__ */ new Set();
101172
101509
  let currentId = memberId;
@@ -101177,6 +101514,35 @@ function isWorldAnimationStructuralMemberFromIndex(memberId, membersById) {
101177
101514
  }
101178
101515
  return false;
101179
101516
  }
101517
+ function worldOverridePathIsStructurallyEligible(memberIdsRootToLeaf, membersById) {
101518
+ for (const memberId of memberIdsRootToLeaf) {
101519
+ if (isWorldAnimationStructuralMemberFromIndex(memberId, membersById)) {
101520
+ return false;
101521
+ }
101522
+ const member = membersById.get(memberId);
101523
+ if (member === void 0) return false;
101524
+ const resolved = resolveMemberFromIndex(member, membersById);
101525
+ if (isStaticMember(resolved) || isReadOnlyMember(resolved)) return false;
101526
+ if (resolved.kind === 13 /* Function */ || resolved.kind === 23 /* NSFunction */ || resolved.kind === 10 /* NSProperty */ || resolved.kind === 6 /* List */ || resolved.kind === 5 /* Dictionary */) {
101527
+ return false;
101528
+ }
101529
+ }
101530
+ return true;
101531
+ }
101532
+ function animationTrackStorage(memberIdsRootToLeaf, membersById, childrenPrefix = []) {
101533
+ if (!worldOverridePathIsStructurallyEligible(memberIdsRootToLeaf, membersById)) {
101534
+ return null;
101535
+ }
101536
+ const path = [...childrenPrefix, ...memberIdsRootToLeaf];
101537
+ for (let index = path.length - 1; index >= 0; index -= 1) {
101538
+ const memberId = path[index];
101539
+ if (memberId === void 0) continue;
101540
+ const storage = declaredMemberStorageFromIndex(memberId, membersById);
101541
+ if (storage === 0 /* Inherit */) continue;
101542
+ return storage === 1 /* Immutable */ ? null : storage;
101543
+ }
101544
+ return null;
101545
+ }
101180
101546
  function assertAnimationClipDocumentValid(document, scope) {
101181
101547
  const context = new AnimationValidationContext(document);
101182
101548
  context.validateSegments(scope);
@@ -101204,7 +101570,6 @@ var init_animation_clips = __esm({
101204
101570
  init_member_storage();
101205
101571
  init_neoscript_types();
101206
101572
  init_neoscript_guards();
101207
- init_project_root_members();
101208
101573
  init_members();
101209
101574
  WORLD_ANIMATION_STRUCTURAL_MEMBER_ROOT_IDS = /* @__PURE__ */ new Set([
101210
101575
  WORLD_GRID_CHILDREN_MEMBER_ID,
@@ -101230,17 +101595,11 @@ var init_animation_clips = __esm({
101230
101595
  document.members.map((value) => [value.id, value])
101231
101596
  );
101232
101597
  this.valueById = new Map(document.values.map((value) => [value.id, value]));
101233
- this.storage = new EffectiveStorageResolver({
101234
- classes: document.classes,
101235
- members: document.members,
101236
- rootStorage: buildRootStorageMap(document.project)
101237
- });
101238
101598
  }
101239
101599
  document;
101240
101600
  classById;
101241
101601
  memberById;
101242
101602
  valueById;
101243
- storage;
101244
101603
  classHasWorldKind(classId, worldKind) {
101245
101604
  const visited = /* @__PURE__ */ new Set();
101246
101605
  let current = this.classById.get(classId);
@@ -101316,6 +101675,7 @@ var init_animation_clips = __esm({
101316
101675
  definitionNode: targetDefinition,
101317
101676
  memberPath: [],
101318
101677
  storagePath: [],
101678
+ childrenPrefix: [],
101319
101679
  visited: /* @__PURE__ */ new Set()
101320
101680
  });
101321
101681
  }
@@ -101400,7 +101760,8 @@ var init_animation_clips = __esm({
101400
101760
  overrideNode: overrides,
101401
101761
  definitionNode: child,
101402
101762
  memberPath: [`child:${childId}`],
101403
- storagePath: [...args.childStoragePath],
101763
+ storagePath: [],
101764
+ childrenPrefix: args.childStoragePath,
101404
101765
  visited: /* @__PURE__ */ new Set()
101405
101766
  });
101406
101767
  }
@@ -101743,12 +102104,13 @@ var init_animation_clips = __esm({
101743
102104
  `${args.label} targets "${boundChildName}.${targetEntry.schemaKey}" of kind ${MemberKind[targetMember.kind]}, but its segment plays ${MemberKind[valueBindingMember.kind]} values.`
101744
102105
  );
101745
102106
  }
101746
- if (!this.overrideLeafEligible(targetMember, [
101747
- ...args.childStoragePath,
101748
- targetMember.id
101749
- ])) {
102107
+ if (!this.overrideLeafEligible(
102108
+ targetMember,
102109
+ [targetMember.id],
102110
+ args.childStoragePath
102111
+ )) {
101750
102112
  throw new Error(
101751
- `${args.label} targets "${boundChildName}.${targetEntry.schemaKey}", which is not a writable Save/Session override leaf.`
102113
+ `${args.label} targets "${boundChildName}.${targetEntry.schemaKey}", which is not a writable Save, Session, or Writable override leaf.`
101752
102114
  );
101753
102115
  }
101754
102116
  }
@@ -101918,7 +102280,8 @@ var init_animation_clips = __esm({
101918
102280
  partial: overrideChild.value,
101919
102281
  path,
101920
102282
  schemaKey,
101921
- storagePath: args.storagePath
102283
+ storagePath: args.storagePath,
102284
+ childrenPrefix: args.childrenPrefix
101922
102285
  });
101923
102286
  continue;
101924
102287
  }
@@ -101949,9 +102312,13 @@ var init_animation_clips = __esm({
101949
102312
  });
101950
102313
  continue;
101951
102314
  }
101952
- if (!this.overrideLeafEligible(member, [...args.storagePath, member.id])) {
102315
+ if (!this.overrideLeafEligible(
102316
+ member,
102317
+ [...args.storagePath, member.id],
102318
+ args.childrenPrefix
102319
+ )) {
101953
102320
  throw new Error(
101954
- `Animation clip "${args.clipName}" frame ${args.frameIndex} member "${path.join(".")}" is not a writable Save/Session override leaf.`
102321
+ `Animation clip "${args.clipName}" frame ${args.frameIndex} member "${path.join(".")}" is not a writable Save, Session, or Writable override leaf.`
101955
102322
  );
101956
102323
  }
101957
102324
  }
@@ -101986,12 +102353,13 @@ var init_animation_clips = __esm({
101986
102353
  );
101987
102354
  }
101988
102355
  const kindLabel = MemberKind[kind];
101989
- if (!this.overrideLeafEligible(args.member, [
101990
- ...args.storagePath,
101991
- args.member.id
101992
- ])) {
102356
+ if (!this.overrideLeafEligible(
102357
+ args.member,
102358
+ [...args.storagePath, args.member.id],
102359
+ args.childrenPrefix
102360
+ )) {
101993
102361
  throw new Error(
101994
- `${prefix} ${kindLabel} member "${memberPath3}" cannot take a "${STRUCTURED_LEAF_PARTIAL_KEY}" field override; member "${args.member.name}" is not a writable Save/Session override leaf.`
102362
+ `${prefix} ${kindLabel} member "${memberPath3}" cannot take a "${STRUCTURED_LEAF_PARTIAL_KEY}" field override; member "${args.member.name}" is not a writable Save, Session, or Writable override leaf.`
101995
102363
  );
101996
102364
  }
101997
102365
  const violation = structuredLeafPartialViolation(
@@ -102032,24 +102400,9 @@ var init_animation_clips = __esm({
102032
102400
  throw new Error(`${descent}; its value is not a ${kindLabel} record.`);
102033
102401
  }
102034
102402
  }
102035
- overrideLeafEligible(member, storagePath) {
102036
- if (isReadOnlyMember(member) === true || isStaticMember(member))
102037
- return false;
102038
- if (isWorldAnimationStructuralMember(member.id, this.document.members)) {
102039
- return false;
102040
- }
102041
- if (member.kind === 13 /* Function */ || member.kind === 23 /* NSFunction */ || member.kind === 10 /* NSProperty */ || member.kind === 7 /* Class */ || member.kind === 6 /* List */ || member.kind === 5 /* Dictionary */) {
102042
- return false;
102043
- }
102044
- try {
102045
- const storage = this.storage.effectiveStorageForPath(storagePath);
102046
- return storage === 2 /* Save */ || storage === 3 /* Session */;
102047
- } catch {
102048
- const storages = this.storage.effectiveStorages(member.id);
102049
- return storages.size > 0 && [...storages].every(
102050
- (storage) => storage === 2 /* Save */ || storage === 3 /* Session */
102051
- );
102052
- }
102403
+ overrideLeafEligible(member, storagePath, childrenPrefix) {
102404
+ if (member.kind === 7 /* Class */) return false;
102405
+ return animationTrackStorage(storagePath, this.memberById, childrenPrefix) !== null;
102053
102406
  }
102054
102407
  authoredChildren(targetClassId, definitionNode) {
102055
102408
  const childEntry = mergeStoredInstanceSchema(
@@ -102073,9 +102426,8 @@ var init_animation_clips = __esm({
102073
102426
  (value) => typeof value === "string"
102074
102427
  ) : []
102075
102428
  ),
102076
- // Child values inherit storage from their concrete placement under the
102077
- // owner's resolved Children member. This mirrors the authoring panel's
102078
- // storage path instead of treating a shared child-class leaf as a root.
102429
+ // P93 §5: a child track's declaration walk continues through the
102430
+ // owner's resolved Children member, as the authoring pane's does.
102079
102431
  storagePath: [childEntry.memberId]
102080
102432
  };
102081
102433
  }
@@ -103038,7 +103390,7 @@ function readClass(value) {
103038
103390
  CLASS_VISIBILITY_KINDS,
103039
103391
  `${label} uiVisibility`
103040
103392
  );
103041
- if (value.allowedStorage != null && !isEffectiveMemberStorage(value.allowedStorage)) {
103393
+ if (value.allowedStorage != null && !isClassAllowedStorage(value.allowedStorage)) {
103042
103394
  throw new Error(`${label} allowedStorage is invalid.`);
103043
103395
  }
103044
103396
  if (value.genericParams !== void 0 && value.genericParams !== null) {
@@ -103420,6 +103772,14 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
103420
103772
  const classes = view.classes.map(readClass);
103421
103773
  const interfaces = view.interfaces.map(readInterface);
103422
103774
  const membersById = new Map(members.map((member) => [member.id, member]));
103775
+ for (const [rootId, stamped] of view.rootStorage ?? []) {
103776
+ const root = membersById.get(rootId);
103777
+ if (root === void 0 || root.storage === stamped) continue;
103778
+ const declared = root.storage === void 0 ? "none" : MemberStorageKind[root.storage];
103779
+ throw new Error(
103780
+ `Project root member "${root.name}" (${rootId}) must declare ${MemberStorageKind[stamped]} storage but declares ${declared}.`
103781
+ );
103782
+ }
103423
103783
  const classesById = new Map(
103424
103784
  classes.map((schemaClass2) => [schemaClass2.id, schemaClass2])
103425
103785
  );
@@ -103539,6 +103899,11 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
103539
103899
  `Static member "${member.name}" (${member.id}) must be a plain non-override member.`
103540
103900
  );
103541
103901
  }
103902
+ if (member.storage === 4 /* Writable */) {
103903
+ throw new Error(
103904
+ `Static member "${member.name}" (${member.id}) cannot declare Writable storage; a static member has no placement parent to resolve it against.`
103905
+ );
103906
+ }
103542
103907
  if (member.kind === 21) {
103543
103908
  throw new Error(
103544
103909
  `Generic placeholder member "${member.name}" (${member.id}) cannot be static.`
@@ -103843,6 +104208,19 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
103843
104208
  if (member.mutability === void 0) delete resolved.mutability;
103844
104209
  return resolved;
103845
104210
  };
104211
+ const writableAncestor2 = createWritableAncestorLookup(
104212
+ (id2) => membersById.get(id2)
104213
+ );
104214
+ for (const member of members) {
104215
+ if (member.storage !== 1 /* Immutable */ && member.storage !== 0 /* Inherit */) {
104216
+ continue;
104217
+ }
104218
+ const ancestor = writableAncestor2(member);
104219
+ if (ancestor === null) continue;
104220
+ throw new Error(
104221
+ `Member "${member.name}" (${member.id}) declares ${MemberStorageKind[member.storage]} storage but overrides Writable member "${ancestor.name}" (${ancestor.id}); an override of a Writable member may declare Writable, Save, or Session, or omit storage.`
104222
+ );
104223
+ }
103846
104224
  const rootAndEntryMemberIds = /* @__PURE__ */ new Set();
103847
104225
  for (const owner of members) {
103848
104226
  if (typeof owner.entryMemberId === "string") {
@@ -103984,7 +104362,7 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
103984
104362
  }
103985
104363
  }
103986
104364
  if (rawOwned.id === member.id && isAbstractMember(member)) return;
103987
- if (owned.storage === 2 /* Save */ || owned.storage === 3 /* Session */) {
104365
+ if (owned.storage === 2 /* Save */ || owned.storage === 3 /* Session */ || owned.storage === 4 /* Writable */) {
103988
104366
  throw new Error(
103989
104367
  `Read-only member "${member.name}" has a non-Immutable owned default child "${owned.name}"; ${ownerLabel}.`
103990
104368
  );
@@ -104515,7 +104893,7 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
104515
104893
  return resolved.setterCode === void 0 ? "NSProperty has no setter implementation." : null;
104516
104894
  }
104517
104895
  const storage = resolved.storage;
104518
- if (storage === 2 /* Save */ || storage === 3 /* Session */) {
104896
+ if (storage === 2 /* Save */ || storage === 3 /* Session */ || storage === 4 /* Writable */) {
104519
104897
  return null;
104520
104898
  }
104521
104899
  if (storage === 1 /* Immutable */) {
@@ -106553,6 +106931,14 @@ function assertStagedProjectInterfaceValid(projected, changes) {
106553
106931
  variants: projected.variants ?? [],
106554
106932
  variantFolders: projected.variantFolders ?? [],
106555
106933
  interfaces: projected.interfaces,
106934
+ rootStorage: writtenRootStorage(
106935
+ projected.project,
106936
+ new Set(
106937
+ changes.flatMap(
106938
+ (change) => change.recordKind === "member" ? [change.recordId] : []
106939
+ )
106940
+ )
106941
+ ),
106556
106942
  values: projected.values
106557
106943
  },
106558
106944
  {
@@ -107148,6 +107534,7 @@ var init_project_version_whole_graph_validation = __esm({
107148
107534
  init_core();
107149
107535
  init_animation_clips();
107150
107536
  init_projectInterfaceValidation();
107537
+ init_project_root_members();
107151
107538
  init_project_schema_identifier_validation();
107152
107539
  init_packed_value_write_fold();
107153
107540
  init_project_version_schema_commit();
@@ -109196,7 +109583,15 @@ function lowerMemberKind(context, ownerClass, declaration, id2, owner) {
109196
109583
  deferred: declaration.modifiers.includes("async")
109197
109584
  };
109198
109585
  }
109199
- return lowerFieldMember(context, ownerClass, declaration, id2, common, base);
109586
+ return lowerFieldMember(
109587
+ context,
109588
+ ownerClass,
109589
+ declaration,
109590
+ id2,
109591
+ common,
109592
+ base,
109593
+ "declaration"
109594
+ );
109200
109595
  }
109201
109596
  function lowerUiFunctionAction(context, ownerName, declaration, base, memberId, sourceText) {
109202
109597
  const compiled = context.compiledFunctionBodiesByMemberId.get(memberId) ?? context.compiledFunctionBodiesBySourceName.get(
@@ -109267,6 +109662,7 @@ function memberCommon(context, ownerClass, declaration, id2, owner, base) {
109267
109662
  const storage = annotation(declaration.annotations, "storage");
109268
109663
  const distribution = annotation(declaration.annotations, "distribution");
109269
109664
  const inheritedId = declaration.modifiers.includes("override") || declaration.modifiers.includes("sealed") ? inheritedMemberId(context, ownerClass, declaration.name) : null;
109665
+ assertWritableStorageRules(context, ownerClass, declaration, inheritedId);
109270
109666
  return {
109271
109667
  id: id2,
109272
109668
  source: sourceIdentity2(declaration, "member", declaration.name),
@@ -109343,7 +109739,7 @@ function resolvedMemberStorage(context, memberId, visited = /* @__PURE__ */ new
109343
109739
  }
109344
109740
  return null;
109345
109741
  }
109346
- function lowerFieldMember(context, ownerClass, declaration, id2, commonInput, base) {
109742
+ function lowerFieldMember(context, ownerClass, declaration, id2, commonInput, base, entrySettings) {
109347
109743
  const partial = declaration.type.name === "Partial";
109348
109744
  const fieldType = partial ? requiredTypeArgument(declaration.type, 0) : declaration.type;
109349
109745
  const storedStatic = declaration.modifiers.includes("static") && !declaration.modifiers.includes("readonly");
@@ -109506,6 +109902,7 @@ function lowerFieldMember(context, ownerClass, declaration, id2, commonInput, ba
109506
109902
  );
109507
109903
  }
109508
109904
  const multiselect = fieldType.name === "Set" || selection2 === "Multi";
109905
+ assertNoElementSettings(fieldType, ownerClass, declaration, "lookup");
109509
109906
  return {
109510
109907
  ...common,
109511
109908
  kind: "lookup",
@@ -109540,9 +109937,11 @@ function lowerFieldMember(context, ownerClass, declaration, id2, commonInput, ba
109540
109937
  }
109541
109938
  const multiselect = name === "Set" || selection2 === "Multi";
109542
109939
  if (enumId2 && multiselect) {
109940
+ assertNoElementSettings(fieldType, ownerClass, declaration, "enum");
109543
109941
  return { ...common, kind: "enum", enumId: enumId2, multiselect: true };
109544
109942
  }
109545
109943
  if (entryType.name === "Dialogue" && multiselect) {
109944
+ assertNoElementSettings(fieldType, ownerClass, declaration, "dialogue");
109546
109945
  return {
109547
109946
  ...common,
109548
109947
  kind: "dialogueLookup",
@@ -109567,7 +109966,8 @@ function lowerFieldMember(context, ownerClass, declaration, id2, commonInput, ba
109567
109966
  entryType,
109568
109967
  entryId,
109569
109968
  id2,
109570
- declaringMemberId
109969
+ declaringMemberId,
109970
+ entrySettings
109571
109971
  );
109572
109972
  return {
109573
109973
  ...common,
@@ -109596,7 +109996,8 @@ function lowerFieldMember(context, ownerClass, declaration, id2, commonInput, ba
109596
109996
  entryType,
109597
109997
  entryId,
109598
109998
  id2,
109599
- declaringMemberId
109999
+ declaringMemberId,
110000
+ entrySettings
109600
110001
  );
109601
110002
  return {
109602
110003
  ...common,
@@ -109657,6 +110058,12 @@ function lowerFieldMember(context, ownerClass, declaration, id2, commonInput, ba
109657
110058
  `Unsupported field type ${JSON.stringify(name)} on ${ownerClass.name}.${declaration.name}.`
109658
110059
  );
109659
110060
  }
110061
+ function assertNoElementSettings(fieldType, ownerClass, declaration, kind) {
110062
+ if (!fieldType.arguments[0]?.annotations?.length) return;
110063
+ throw new Error(
110064
+ `Member ${ownerClass.name}.${declaration.name} is a multi-select ${kind}, which has no entry member for element settings. Remove the annotations before its element type.`
110065
+ );
110066
+ }
109660
110067
  function inheritedMember(context, memberId) {
109661
110068
  if (memberId === null) return void 0;
109662
110069
  return context.loweredMembers.get(memberId) ?? context.baseMembers.get(memberId);
@@ -109756,7 +110163,7 @@ function overrideParentMemberId(context, memberId) {
109756
110163
  const overrides = member.modifiers.includes("override") || member.modifiers.includes("sealed");
109757
110164
  return overrides ? inheritedMemberId(context, ownerClass, member.name) : null;
109758
110165
  }
109759
- function lowerCollectionEntry(context, ownerClass, entryType, entryId, parentMemberId, declaringMemberId) {
110166
+ function lowerCollectionEntry(context, ownerClass, entryType, entryId, parentMemberId, declaringMemberId, entrySettings) {
109760
110167
  const declared = declaredCollectionEntryType(context, declaringMemberId);
109761
110168
  const expected = declared === null ? null : resolveManifestTypeInDescendant(
109762
110169
  context,
@@ -109783,7 +110190,7 @@ function lowerCollectionEntry(context, ownerClass, entryType, entryId, parentMem
109783
110190
  context.entryTypesByEntryId.set(entryId, entryDeclarationType);
109784
110191
  if (context.loweredMembers.has(entryId)) return;
109785
110192
  const base = context.baseMembers.get(entryId);
109786
- if (base) {
110193
+ if (base !== void 0 && entrySettings === "stored") {
109787
110194
  context.loweredMembers.set(base.id, {
109788
110195
  ...base,
109789
110196
  owner: { kind: "collectionEntry", parentMemberId }
@@ -109801,7 +110208,7 @@ function lowerCollectionEntry(context, ownerClass, entryType, entryId, parentMem
109801
110208
  name: "Item",
109802
110209
  type: entryDeclarationType,
109803
110210
  modifiers: [],
109804
- annotations: [],
110211
+ annotations: entryDeclarationType.annotations ?? [],
109805
110212
  initializer: null,
109806
110213
  body: null,
109807
110214
  parameters: []
@@ -109814,18 +110221,89 @@ function lowerCollectionEntry(context, ownerClass, entryType, entryId, parentMem
109814
110221
  { kind: "collectionEntry", parentMemberId },
109815
110222
  base
109816
110223
  );
110224
+ const lowered = lowerFieldMember(
110225
+ context,
110226
+ entryOwnerClass,
110227
+ declaration,
110228
+ entryId,
110229
+ common,
110230
+ base,
110231
+ entrySettings
110232
+ );
110233
+ if (base !== void 0 && entryTarget(base) !== entryTarget(lowered)) {
110234
+ throw new Error(
110235
+ `Collection member ${ownerClass.name}.${parentMemberId} declares element type ${formatManifestType(entryDeclarationType)}, but its stored entry member is a ${base.kind} of another type. An existing collection's element type cannot change; declare a new member instead.`
110236
+ );
110237
+ }
109817
110238
  context.loweredMembers.set(
109818
110239
  entryId,
109819
- lowerFieldMember(
109820
- context,
109821
- entryOwnerClass,
109822
- declaration,
109823
- entryId,
109824
- common,
109825
- base
109826
- )
110240
+ base === void 0 ? lowered : {
110241
+ ...withEntrySettings(base, lowered),
110242
+ owner: { kind: "collectionEntry", parentMemberId }
110243
+ }
109827
110244
  );
109828
110245
  }
110246
+ function entryTarget(member) {
110247
+ switch (member.kind) {
110248
+ case "class":
110249
+ return `class:${member.classId}`;
110250
+ case "enum":
110251
+ return `enum:${member.enumId}`;
110252
+ case "generic":
110253
+ return `generic:${member.genericParamId}`;
110254
+ default:
110255
+ return member.kind;
110256
+ }
110257
+ }
110258
+ function withEntrySettings(base, lowered) {
110259
+ switch (lowered.kind) {
110260
+ case "string":
110261
+ return base.kind === lowered.kind ? {
110262
+ ...base,
110263
+ localizable: lowered.localizable,
110264
+ searchKey: lowered.searchKey
110265
+ } : base;
110266
+ case "int":
110267
+ return base.kind === lowered.kind ? { ...base, min: lowered.min, max: lowered.max } : base;
110268
+ case "float":
110269
+ return base.kind === lowered.kind ? {
110270
+ ...base,
110271
+ min: lowered.min,
110272
+ max: lowered.max,
110273
+ decimalPoints: lowered.decimalPoints
110274
+ } : base;
110275
+ case "decimal":
110276
+ return base.kind === lowered.kind ? {
110277
+ ...base,
110278
+ min: lowered.min,
110279
+ max: lowered.max,
110280
+ decimalPoints: lowered.decimalPoints
110281
+ } : base;
110282
+ case "list":
110283
+ return base.kind === lowered.kind ? { ...base, listKind: lowered.listKind } : base;
110284
+ case "enum":
110285
+ return base.kind === lowered.kind ? { ...base, multiselect: lowered.multiselect } : base;
110286
+ case "lookup":
110287
+ return base.kind === lowered.kind ? {
110288
+ ...base,
110289
+ collectionMemberId: lowered.collectionMemberId,
110290
+ collectionValueId: lowered.collectionValueId,
110291
+ multiselect: lowered.multiselect
110292
+ } : base;
110293
+ case "dialogueLookup":
110294
+ return base.kind === lowered.kind ? {
110295
+ ...base,
110296
+ dialogueGroupId: lowered.dialogueGroupId,
110297
+ multiselect: lowered.multiselect
110298
+ } : base;
110299
+ case "sprite":
110300
+ return base.kind === lowered.kind ? { ...base, templateId: lowered.templateId } : base;
110301
+ case "audio":
110302
+ return base.kind === lowered.kind ? { ...base, templateId: lowered.templateId } : base;
110303
+ default:
110304
+ return base;
110305
+ }
110306
+ }
109829
110307
  function declaredCollectionEntryType(context, declaringMemberId) {
109830
110308
  const placement = context.sourceMembersById.get(declaringMemberId);
109831
110309
  if (placement === void 0) return null;
@@ -111065,7 +111543,8 @@ function lowerGenericArgument(context, ownerClass, type, memberId, genericParamI
111065
111543
  requiredTypeArgument(type, base.kind === "list" ? 0 : 1),
111066
111544
  base.entryMemberId,
111067
111545
  memberId,
111068
- memberId
111546
+ memberId,
111547
+ "stored"
111069
111548
  );
111070
111549
  }
111071
111550
  return;
@@ -111106,7 +111585,8 @@ function lowerGenericArgument(context, ownerClass, type, memberId, genericParamI
111106
111585
  storage: base?.storage ?? null,
111107
111586
  storageKey: base?.storageKey ?? null
111108
111587
  },
111109
- base
111588
+ base,
111589
+ "stored"
111110
111590
  )
111111
111591
  );
111112
111592
  }
@@ -111219,7 +111699,74 @@ function numberArgument(value, name) {
111219
111699
  }
111220
111700
  function storageValue(value, name) {
111221
111701
  const enumValue2 = contextualEnumArgument(value, name)?.toLowerCase();
111222
- return enumValue2 === "immutable" || enumValue2 === "save" || enumValue2 === "session" ? enumValue2 : null;
111702
+ return enumValue2 === "immutable" || enumValue2 === "save" || enumValue2 === "session" || enumValue2 === "writable" ? enumValue2 : null;
111703
+ }
111704
+ function assertWritableStorageRules(context, ownerClass, declaration, inheritedId) {
111705
+ const site = `${ownerClass.name}.${declaration.name}`;
111706
+ const storage = annotation(declaration.annotations, "storage");
111707
+ const declared = storage ? contextualEnumArgument(storage, "allowed")?.toLowerCase() : void 0;
111708
+ if (declared === "writable" && declaration.modifiers.includes("static")) {
111709
+ throw new Error(
111710
+ `Static member ${site} cannot declare Writable storage: a static member has no parent to resolve it against. Declare Save or Session.`
111711
+ );
111712
+ }
111713
+ if (inheritedId === null) return;
111714
+ const ancestor = writableAncestor(context, inheritedId);
111715
+ if (ancestor === null) return;
111716
+ if (declared === "immutable") {
111717
+ throw new Error(
111718
+ `${site} cannot declare Immutable storage because it overrides ${ancestor}, which declares Writable. Declare Writable, Save, or Session, or omit @storage.`
111719
+ );
111720
+ }
111721
+ if (declared === "inherit") {
111722
+ throw new Error(
111723
+ `${site} cannot declare Inherit storage because it overrides ${ancestor}, which declares Writable. Declare Writable, Save, or Session, or omit @storage.`
111724
+ );
111725
+ }
111726
+ }
111727
+ function writableAncestor(context, memberId) {
111728
+ const memo = context.writableAncestors;
111729
+ const chain = /* @__PURE__ */ new Set();
111730
+ let currentId = memberId;
111731
+ let found = null;
111732
+ while (currentId !== null) {
111733
+ const known = memo.get(currentId);
111734
+ if (known !== void 0) {
111735
+ found = known;
111736
+ break;
111737
+ }
111738
+ if (chain.has(currentId)) break;
111739
+ chain.add(currentId);
111740
+ const step = storageChainStep(context, currentId);
111741
+ if (step === null) break;
111742
+ if (step.storage === "writable") {
111743
+ found = step.label;
111744
+ break;
111745
+ }
111746
+ currentId = step.overrideOf;
111747
+ }
111748
+ for (const id2 of chain) memo.set(id2, found);
111749
+ return found;
111750
+ }
111751
+ function storageChainStep(context, memberId) {
111752
+ const sourcePlacement = context.sourceMembersById.get(memberId);
111753
+ if (sourcePlacement !== void 0) {
111754
+ const { ownerClass, member } = sourcePlacement;
111755
+ const storage = annotation(member.annotations, "storage");
111756
+ return {
111757
+ label: `${ownerClass.name}.${member.name}`,
111758
+ storage: storage ? storageValue(storage, "allowed") : null,
111759
+ overrideOf: member.modifiers.includes("override") || member.modifiers.includes("sealed") ? inheritedMemberId(context, ownerClass, member.name) : null
111760
+ };
111761
+ }
111762
+ const persisted = context.baseMembers.get(memberId);
111763
+ if (persisted === void 0) return null;
111764
+ const ownerName = persisted.owner.kind === "classMember" ? context.baseClasses.get(persisted.owner.classId)?.name : void 0;
111765
+ return {
111766
+ label: ownerName === void 0 ? persisted.name : `${ownerName}.${persisted.name}`,
111767
+ storage: persisted.storage,
111768
+ overrideOf: persisted.overrideOf
111769
+ };
111223
111770
  }
111224
111771
  function referenceIdArgument(value, name) {
111225
111772
  const raw = argument(value, name);
@@ -112199,6 +112746,7 @@ function lowerProjectSchemaV4(base, analysis, options = {}) {
112199
112746
  enumOptionsByName,
112200
112747
  loweredMembers: /* @__PURE__ */ new Map(),
112201
112748
  entryTypesByEntryId: /* @__PURE__ */ new Map(),
112749
+ writableAncestors: /* @__PURE__ */ new Map(),
112202
112750
  placements: /* @__PURE__ */ new Map(),
112203
112751
  staticValueIdsBySymbol: staticValueIdsBySymbol3,
112204
112752
  settleInitializerReferences: createSchemaInitializerReferenceSettlerV4({
@@ -115274,6 +115822,8 @@ var init_root_value_paths = __esm({
115274
115822
  // src/project-source/packed-value-parity.ts
115275
115823
  function logicalValueBaseRecordsV4(records2) {
115276
115824
  let expanded = null;
115825
+ const parentByPackedId = /* @__PURE__ */ new Map();
115826
+ const rootByPackedId = /* @__PURE__ */ new Map();
115277
115827
  for (const [key, record6] of Object.entries(records2)) {
115278
115828
  if (record6.recordKind !== "value") continue;
115279
115829
  if (!isObjectRecord2(record6.data)) continue;
@@ -115285,6 +115835,12 @@ function logicalValueBaseRecordsV4(records2) {
115285
115835
  );
115286
115836
  }
115287
115837
  const decoded = decodePackedValueRow(authoredData);
115838
+ for (const [parentId, childIds] of decoded.packedChildIdsByParentId) {
115839
+ for (const childId of childIds) {
115840
+ parentByPackedId.set(childId, parentId);
115841
+ rootByPackedId.set(childId, record6.recordId);
115842
+ }
115843
+ }
115288
115844
  expanded ??= { ...records2 };
115289
115845
  expanded[key] = { ...record6, data: decoded.row };
115290
115846
  for (const child of decoded.children) {
@@ -115297,7 +115853,10 @@ function logicalValueBaseRecordsV4(records2) {
115297
115853
  };
115298
115854
  }
115299
115855
  }
115300
- return expanded ?? records2;
115856
+ return {
115857
+ records: expanded ?? records2,
115858
+ residency: { parentByPackedId, rootByPackedId }
115859
+ };
115301
115860
  }
115302
115861
  function foldCandidateValueRowsV4(args) {
115303
115862
  if (args.candidates.size === 0) return EMPTY_FOLD;
@@ -115309,7 +115868,11 @@ function foldCandidateValueRowsV4(args) {
115309
115868
  rows.push(row);
115310
115869
  inputById.set(valueId, row);
115311
115870
  }
115312
- const fold = foldPackedValueRows({ rows, document: args.schema });
115871
+ const fold = foldPackedValueRows({
115872
+ rows,
115873
+ document: args.schema,
115874
+ residency: args.residency
115875
+ });
115313
115876
  if (fold.rootByFoldedId.size === 0) return EMPTY_FOLD;
115314
115877
  const adoptedRootIds = /* @__PURE__ */ new Set();
115315
115878
  for (const [childId, rootId] of fold.rootByFoldedId) {
@@ -116410,9 +116973,7 @@ function computeWorkspaceStatus(workspace, options) {
116410
116973
  binaryFiles: []
116411
116974
  };
116412
116975
  }
116413
- const loweringRecords = logicalValueBaseRecordsV4(
116414
- loweringBaseRecords(workspace.state.records)
116415
- );
116976
+ const { records: loweringRecords, residency: packedResidency } = logicalValueBaseRecordsV4(loweringBaseRecords(workspace.state.records));
116416
116977
  const baseDocuments = schemaBaseDocuments(workspace);
116417
116978
  const staticMemberOwnershipRecoveries = [];
116418
116979
  const baseManifest = baseDocuments.length === 0 ? void 0 : documentsToProjectSchemaManifest(baseDocuments, {
@@ -116978,6 +117539,14 @@ function computeWorkspaceStatus(workspace, options) {
116978
117539
  workspace.config.projectId
116979
117540
  ),
116980
117541
  reconstructed: reconstructed3,
117542
+ changes,
117543
+ residency: packedResidency,
117544
+ rewrittenValueIds: valueLowerRegistry.localizationConversionValueIds
117545
+ });
117546
+ writeLocalizationConversionRowsV4({
117547
+ workspace,
117548
+ rootByPackedId: packedResidency.rootByPackedId,
117549
+ valueIds: valueLowerRegistry.localizationConversionValueIds,
116981
117550
  changes
116982
117551
  });
116983
117552
  reportPhase("packed-value-fold", "Checking initializers\u2026");
@@ -117612,7 +118181,7 @@ function applyPackedValueFoldV4(args) {
117612
118181
  candidates.set(record6.recordId, record6.fullData);
117613
118182
  const logicalBase = args.loweringRecords[key];
117614
118183
  const physicalBase = args.workspace.state.records[key];
117615
- if (logicalBase === void 0 || physicalBase === void 0 || physicalBase.conflictServerHash !== void 0 || isPendingId(record6.recordId) || !recordsSemanticallyEqual("value", record6.fullData, logicalBase.data)) {
118184
+ if (logicalBase === void 0 || physicalBase === void 0 || physicalBase.conflictServerHash !== void 0 || isPendingId(record6.recordId) || args.rewrittenValueIds.has(record6.recordId) || !recordsSemanticallyEqual("value", record6.fullData, logicalBase.data)) {
117616
118185
  touchedValueIds.add(record6.recordId);
117617
118186
  }
117618
118187
  }
@@ -117620,6 +118189,7 @@ function applyPackedValueFoldV4(args) {
117620
118189
  candidates,
117621
118190
  base: args.loweringRecords,
117622
118191
  physicalBase: args.workspace.state.records,
118192
+ residency: args.residency,
117623
118193
  touchedValueIds,
117624
118194
  projectId: args.workspace.config.projectId,
117625
118195
  schema: args.schema
@@ -117704,6 +118274,32 @@ function applyPackedValueFoldV4(args) {
117704
118274
  args.reconstructed.set(key, { ...record6, fullData: packedBody });
117705
118275
  }
117706
118276
  }
118277
+ function writeLocalizationConversionRowsV4(args) {
118278
+ if (args.valueIds.size === 0) return;
118279
+ const records2 = args.workspace.state.records;
118280
+ const written = new Set(
118281
+ args.changes.map(
118282
+ (change) => recordStateKey(change.recordKind, change.recordId)
118283
+ )
118284
+ );
118285
+ for (const valueId of args.valueIds) {
118286
+ const rootId = args.rootByPackedId.get(valueId) ?? valueId;
118287
+ const key = recordStateKey("value", rootId);
118288
+ if (written.has(key)) continue;
118289
+ const base = records2[key];
118290
+ if (base === void 0 || !isObjectRecord2(base.data)) continue;
118291
+ written.add(key);
118292
+ args.changes.push(
118293
+ recordUpsertChange({
118294
+ base,
118295
+ recordKind: "value",
118296
+ recordId: base.recordId,
118297
+ file: base.file ?? null,
118298
+ nextData: base.data
118299
+ })
118300
+ );
118301
+ }
118302
+ }
117707
118303
  function packedFoldSchemaV4(documents, base, projectId) {
117708
118304
  const seedEnvelope = { projectId, createdAt: 0, updatedAt: 0 };
117709
118305
  const completed = /* @__PURE__ */ new Map();
@@ -120257,6 +120853,7 @@ function createValueLowerRegistryV4(options = {}) {
120257
120853
  pendingContainerChildCounts: /* @__PURE__ */ new Map(),
120258
120854
  pendingLocalizedTexts: /* @__PURE__ */ new Map(),
120259
120855
  pendingBindingMembersByClassId: /* @__PURE__ */ new Map(),
120856
+ localizationConversionValueIds: /* @__PURE__ */ new Set(),
120260
120857
  referenceObligations: [],
120261
120858
  initAuthoredRowIds: /* @__PURE__ */ new Map(),
120262
120859
  loweringFailures: [],
@@ -120376,6 +120973,7 @@ function buildValueLowerContext(state, manifest, options = {}) {
120376
120973
  pendingValues: registry.pendingValues,
120377
120974
  pendingContainerChildCounts: registry.pendingContainerChildCounts,
120378
120975
  pendingLocalizedTexts: registry.pendingLocalizedTexts,
120976
+ localizationConversionValueIds: registry.localizationConversionValueIds,
120379
120977
  loweredMemberIdByValueId: /* @__PURE__ */ new Map(),
120380
120978
  storedClassSchemaMemberIds: /* @__PURE__ */ new Map(),
120381
120979
  pendingBindingMembersByClassId: registry.pendingBindingMembersByClassId,
@@ -123226,6 +123824,10 @@ function retainStoredValueSubgraph(context, valueId, source, visited, member, en
123226
123824
  `Localizable value ${valueId} has no existing localized-text link.`
123227
123825
  );
123228
123826
  }
123827
+ if (pulledStringMemberIsPlain(context.state, owningMember.id)) {
123828
+ context.localizationConversionValueIds.add(valueId);
123829
+ return;
123830
+ }
123229
123831
  const textState = context.state[`localized-text:${textId}`];
123230
123832
  if (!isObjectRecord2(textState?.data)) {
123231
123833
  throw new Error(`Localized text ${textId} was not pulled.`);
@@ -123976,6 +124578,10 @@ function lowerStringValue(context, member, expression, base, source) {
123976
124578
  `Localizable value ${String(base.id)} has no existing localized-text link.`
123977
124579
  );
123978
124580
  }
124581
+ if (pulledStringMemberIsPlain(context.state, member.id)) {
124582
+ context.localizationConversionValueIds.add(String(base.id));
124583
+ return expression.value;
124584
+ }
123979
124585
  return lowerLinkedLocalizedText(
123980
124586
  context,
123981
124587
  base.value,
@@ -123983,6 +124589,19 @@ function lowerStringValue(context, member, expression, base, source) {
123983
124589
  source
123984
124590
  );
123985
124591
  }
124592
+ function pulledStringMemberIsPlain(state, memberId) {
124593
+ const visited = /* @__PURE__ */ new Set();
124594
+ let id2 = memberId;
124595
+ while (typeof id2 === "string" && !visited.has(id2)) {
124596
+ visited.add(id2);
124597
+ const data = state[`member:${id2}`]?.data;
124598
+ if (!isObjectRecord2(data)) return false;
124599
+ if (data.format !== void 0)
124600
+ return data.format === 1 /* Plain */;
124601
+ id2 = data.extendsMemberId;
124602
+ }
124603
+ return false;
124604
+ }
123986
124605
  function lowerLinkedLocalizedText(context, textId, value, source) {
123987
124606
  const textState = context.state[`localized-text:${textId}`];
123988
124607
  if (!isObjectRecord2(textState?.data)) {
@@ -127629,7 +128248,7 @@ var init_project_document_cache = __esm({
127629
128248
  init_src();
127630
128249
  init_project_documents();
127631
128250
  PROJECT_SOURCE_BUILD_CACHE_PATH = ".neo/build/project-source-analysis-v4.json";
127632
- PROJECT_SOURCE_BUILD_CACHE_REVISION = 1;
128251
+ PROJECT_SOURCE_BUILD_CACHE_REVISION = 2;
127633
128252
  PROJECT_SOURCE_DOCUMENT_BUILD_CACHE_PATH = ".neo/build/project-source-documents-v1.json";
127634
128253
  PROJECT_SOURCE_DOCUMENT_BUILD_CACHE_REVISION = 1;
127635
128254
  }
@@ -138866,7 +139485,7 @@ var init_registry2 = __esm({
138866
139485
  "schema-contract/registry.mjs"() {
138867
139486
  "use strict";
138868
139487
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
138869
- cliVersion: "0.54.1",
139488
+ cliVersion: "0.56.0",
138870
139489
  projectFileUploadBatchSize: 32,
138871
139490
  documentRecords: {
138872
139491
  member: {
@@ -139208,8 +139827,8 @@ var init_registry2 = __esm({
139208
139827
  sdkDeclarations: {
139209
139828
  attributes: {
139210
139829
  enums: {
139211
- NeoStorage: ["Inherit", "Immutable", "Save", "Session"],
139212
- NeoAllowedStorage: ["Any", "Immutable", "Save", "Session"],
139830
+ NeoStorage: ["Inherit", "Immutable", "Save", "Session", "Writable"],
139831
+ NeoAllowedStorage: ["Any", "Immutable", "Save", "Session", "Writable"],
139213
139832
  NeoListKind: ["Ordered", "Unordered"],
139214
139833
  NeoDictionaryKeyKind: ["String", "Enum"],
139215
139834
  NeoClassVisibility: ["Visible", "Hidden"],
@@ -146687,7 +147306,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
146687
147306
  async function main() {
146688
147307
  const args = parseArgs(process.argv.slice(2));
146689
147308
  if (args.command === "--version") {
146690
- console.log("0.54.1");
147309
+ console.log("0.56.0");
146691
147310
  return;
146692
147311
  }
146693
147312
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {