@neocompose/cli 0.56.1 → 0.57.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
@@ -1359,7 +1359,7 @@ function indexLocals(tokens, pairs, lexed, diagnostics) {
1359
1359
  }
1360
1360
  const loop = tryParseLoopLocal(tokens, index, pairs, lexed, diagnostics);
1361
1361
  if (loop) {
1362
- locals.push(loop.local);
1362
+ locals.push(...loop.locals);
1363
1363
  index = loop.resumeTokenIndex;
1364
1364
  continue;
1365
1365
  }
@@ -1793,7 +1793,7 @@ function tryParseLoopLocal(tokens, start, pairs, lexed, diagnostics) {
1793
1793
  });
1794
1794
  }
1795
1795
  return {
1796
- local: { ...declaration.local, scopeEnd },
1796
+ locals: [{ ...declaration.local, scopeEnd }],
1797
1797
  resumeTokenIndex: declaration.endTokenIndex
1798
1798
  };
1799
1799
  }
@@ -1805,22 +1805,65 @@ function tryParseLoopLocal(tokens, start, pairs, lexed, diagnostics) {
1805
1805
  const inIndex = start + 2 + inOffset;
1806
1806
  const name = tokens[inIndex - 1];
1807
1807
  const first = tokens[start + 2];
1808
- if (!name || name.kind !== "identifier" || !first) return null;
1808
+ if (!first) return null;
1809
1809
  const inferred = first.kind === "identifier" && first.text === NEOSCRIPT_INFERRED_LOCAL_KEYWORD;
1810
+ const receiver = tokens.slice(inIndex + 1, closeIndex);
1811
+ const local = (token, typeTokens, key) => ({
1812
+ name: token.text,
1813
+ nameRange: token.range,
1814
+ typeTokens,
1815
+ inferred,
1816
+ ...inferred ? { contextualKeywordRange: first.range } : {},
1817
+ initializerTokens: receiver,
1818
+ collectionIteration: true,
1819
+ ...key ? { collectionIterationKey: true } : {},
1820
+ declarationRange: lexed.source.range(first.start, token.end),
1821
+ scopeStart: tokens[closeIndex]?.end ?? token.end,
1822
+ scopeEnd,
1823
+ lambdaParameter: false
1824
+ });
1825
+ const tupleOpenIndex = start + (inferred ? 3 : 2);
1826
+ const tupleOpen = tokens[tupleOpenIndex];
1827
+ if (tupleOpen?.kind === "punctuation" && tupleOpen.text === "(") {
1828
+ const tupleCloseIndex = pairs.get(tupleOpenIndex);
1829
+ if (tupleCloseIndex !== inIndex - 1) return null;
1830
+ let commaIndex = -1;
1831
+ let angleDepth = 0;
1832
+ for (let cursor = tupleOpenIndex + 1; cursor < tupleCloseIndex; cursor++) {
1833
+ const text = tokens[cursor]?.text;
1834
+ if (text === "<") angleDepth++;
1835
+ if (text === ">") angleDepth--;
1836
+ if (text === "," && angleDepth === 0) {
1837
+ commaIndex = cursor;
1838
+ break;
1839
+ }
1840
+ }
1841
+ if (commaIndex < 0) return null;
1842
+ const keyName = tokens[commaIndex - 1];
1843
+ const valueName = tokens[tupleCloseIndex - 1];
1844
+ if (keyName?.kind !== "identifier" || valueName?.kind !== "identifier")
1845
+ return null;
1846
+ return {
1847
+ locals: [
1848
+ local(
1849
+ keyName,
1850
+ inferred ? [] : tokens.slice(tupleOpenIndex + 1, commaIndex - 1),
1851
+ true
1852
+ ),
1853
+ local(
1854
+ valueName,
1855
+ inferred ? [] : tokens.slice(commaIndex + 1, tupleCloseIndex - 1),
1856
+ false
1857
+ )
1858
+ ],
1859
+ resumeTokenIndex: inIndex - 1
1860
+ };
1861
+ }
1862
+ if (!name || name.kind !== "identifier") return null;
1810
1863
  return {
1811
- local: {
1812
- name: name.text,
1813
- nameRange: name.range,
1814
- typeTokens: inferred ? [] : tokens.slice(start + 2, inIndex - 1),
1815
- inferred,
1816
- ...inferred ? { contextualKeywordRange: first.range } : {},
1817
- initializerTokens: tokens.slice(inIndex + 1, closeIndex),
1818
- collectionIteration: true,
1819
- declarationRange: lexed.source.range(first.start, name.end),
1820
- scopeStart: tokens[closeIndex]?.end ?? name.end,
1821
- scopeEnd,
1822
- lambdaParameter: false
1823
- },
1864
+ locals: [
1865
+ local(name, inferred ? [] : tokens.slice(start + 2, inIndex - 1), false)
1866
+ ],
1824
1867
  resumeTokenIndex: inIndex - 1
1825
1868
  };
1826
1869
  }
@@ -2877,14 +2920,25 @@ var init_executable_parser = __esm({
2877
2920
  const token = this.expect("keyword", "foreach");
2878
2921
  this.expect("punctuation", "(");
2879
2922
  const inferred = this.peek().kind === "identifier" && this.peek().text === NEOSCRIPT_INFERRED_LOCAL_KEYWORD;
2923
+ if (inferred) this.next();
2924
+ const deconstructed = this.peek().kind === "punctuation" && this.peek().text === "(";
2925
+ if (deconstructed) this.next();
2880
2926
  let type;
2881
2927
  if (inferred) {
2882
- this.next();
2883
2928
  type = null;
2884
2929
  } else {
2885
2930
  type = this.parseType();
2886
2931
  }
2887
- const name = this.expect("identifier");
2932
+ const firstName = this.expect("identifier");
2933
+ let key;
2934
+ let name = firstName;
2935
+ if (deconstructed) {
2936
+ key = { name: firstName.text, type };
2937
+ this.expect("punctuation", ",");
2938
+ type = inferred ? null : this.parseType();
2939
+ name = this.expect("identifier");
2940
+ this.expect("punctuation", ")");
2941
+ }
2888
2942
  this.expect("keyword", "in");
2889
2943
  const collection = this.parseExpr();
2890
2944
  this.expect("punctuation", ")");
@@ -2892,6 +2946,7 @@ var init_executable_parser = __esm({
2892
2946
  kind: "forEach",
2893
2947
  type,
2894
2948
  name: name.text,
2949
+ ...key ? { key } : {},
2895
2950
  collection,
2896
2951
  body: this.parseStatementBody(),
2897
2952
  pos: at(token)
@@ -5834,6 +5889,9 @@ function collectionParts(type) {
5834
5889
  function collectionPartsFor(expression) {
5835
5890
  return collectionParts(expression.type);
5836
5891
  }
5892
+ function isCollectionPath(expression) {
5893
+ return expression.kind === "ident" || expression.kind === "member" && !expression.optional && isCollectionPath(expression.receiver);
5894
+ }
5837
5895
  function collectionOperationValueType(expression, collection) {
5838
5896
  if (isLookupSelectionCollection(expression, collection)) {
5839
5897
  return { kind: "primitive", name: "string" };
@@ -6934,6 +6992,12 @@ var init_strict_resolver = __esm({
6934
6992
  };
6935
6993
  }
6936
6994
  case "forEach": {
6995
+ if (statement.key && !isCollectionPath(statement.collection)) {
6996
+ throw new CompileError(
6997
+ "Assign the dictionary to a local before deconstructing it in foreach.",
6998
+ statement.collection.pos
6999
+ );
7000
+ }
6937
7001
  const collection = this.resolveExpression(statement.collection, scope);
6938
7002
  if (isNullable(collection.type)) {
6939
7003
  throw new CompileError(
@@ -6948,36 +7012,88 @@ var init_strict_resolver = __esm({
6948
7012
  statement.collection.pos
6949
7013
  );
6950
7014
  }
7015
+ if (statement.key && parts.kind !== "dictionary") {
7016
+ throw new CompileError(
7017
+ `foreach key/value deconstruction requires a Dictionary, got ${this.describe(collection.type)}`,
7018
+ statement.collection.pos
7019
+ );
7020
+ }
6951
7021
  this.assertLocalNameAvailable(statement.name, scope, statement.pos);
6952
- const inferredType = parts.valueType;
6953
- const bindingType = statement.type ? this.resolveType(statement.type) : inferredType;
6954
- if (statement.type) {
7022
+ if (statement.key) {
7023
+ this.assertLocalNameAvailable(
7024
+ statement.key.name,
7025
+ scope,
7026
+ statement.pos
7027
+ );
7028
+ if (statement.key.name === statement.name) {
7029
+ throw new CompileError(
7030
+ "foreach key and value need different names.",
7031
+ statement.pos
7032
+ );
7033
+ }
7034
+ }
7035
+ const inferredType = statement.key ? parts.keyType : parts.valueType;
7036
+ const declared = statement.key ? statement.key.type : statement.type;
7037
+ const bindingType = declared ? this.resolveType(declared) : inferredType;
7038
+ if (declared) {
6955
7039
  this.requireAssignable(
6956
7040
  inferredType,
6957
7041
  bindingType,
6958
7042
  statement.pos,
6959
- "foreach iterator"
7043
+ statement.key ? "foreach key" : "foreach iterator"
6960
7044
  );
6961
7045
  }
6962
7046
  const binding = variable(
6963
- statement.name,
7047
+ statement.key?.name ?? statement.name,
6964
7048
  bindingType,
6965
7049
  void 0,
6966
7050
  this.project
6967
7051
  );
7052
+ const iterationCollection = statement.key ? this.selectDictionaryKeys(collection, parts) : collection;
6968
7053
  const bindingWritability = collection.entryWritability ?? collection.writability ?? "runtime" /* Runtime */;
7054
+ const collectionWriteRoot = this.expressionWriteRoot(collection, scope);
6969
7055
  const loopScope = new Scope(scope);
6970
7056
  loopScope.define(
6971
7057
  scopeVariable(
6972
- statement.name,
7058
+ statement.key?.name ?? statement.name,
6973
7059
  binding,
6974
7060
  bindingType,
6975
7061
  bindingWritability,
6976
7062
  bindingWritability,
6977
- collection.writeRoot ?? this.writeThroughRoot(collection.pointer, scope),
7063
+ collectionWriteRoot,
6978
7064
  "foreach"
6979
7065
  )
6980
7066
  );
7067
+ if (statement.key) {
7068
+ const valueType = statement.type ? this.resolveType(statement.type) : parts.valueType;
7069
+ if (statement.type) {
7070
+ this.requireAssignable(
7071
+ parts.valueType,
7072
+ valueType,
7073
+ statement.pos,
7074
+ "foreach value"
7075
+ );
7076
+ }
7077
+ const indexed = this.resolveIndex(
7078
+ statement.collection,
7079
+ { kind: "ident", name: statement.key.name, pos: statement.pos },
7080
+ loopScope,
7081
+ statement.pos,
7082
+ false
7083
+ );
7084
+ loopScope.define({
7085
+ name: statement.name,
7086
+ type: valueType,
7087
+ variableId: statement.name,
7088
+ pointer: indexed.pointer,
7089
+ ...indexed.writability ? {
7090
+ writability: indexed.writability,
7091
+ ownership: indexed.writability
7092
+ } : {},
7093
+ writeRoot: collectionWriteRoot,
7094
+ readonlyBinding: "foreach"
7095
+ });
7096
+ }
6981
7097
  const iterationScope = new Scope(loopScope);
6982
7098
  invalidateLoopEntryNarrowingsAssignedBy(
6983
7099
  iterationScope,
@@ -7025,8 +7141,8 @@ var init_strict_resolver = __esm({
7025
7141
  readonly: true,
7026
7142
  writability: bindingWritability
7027
7143
  },
7028
- collectionPointer: collection.pointer,
7029
- collectionTypeInfo: collection.wireType ?? toWireType(collection.type, this.project),
7144
+ collectionPointer: iterationCollection.pointer,
7145
+ collectionTypeInfo: iterationCollection.wireType ?? toWireType(iterationCollection.type, this.project),
7030
7146
  instructions
7031
7147
  };
7032
7148
  }
@@ -7468,6 +7584,8 @@ var init_strict_resolver = __esm({
7468
7584
  let label = "foreach iterator";
7469
7585
  if (local.readonlyBinding === "catch") label = "catch parameter";
7470
7586
  if (local.readonlyBinding === "capture") label = "captured value";
7587
+ if (local.readonlyBinding === "enumKey")
7588
+ label = "enum dictionary key parameter";
7471
7589
  throw new CompileError(
7472
7590
  `Cannot assign to ${label} '${local.name}' because it is read-only.`,
7473
7591
  statement.pos
@@ -11631,6 +11749,67 @@ var init_strict_resolver = __esm({
11631
11749
  }
11632
11750
  return value.pointer;
11633
11751
  }
11752
+ selectDictionaryKeys(dictionary, parts) {
11753
+ const key = this.collectionLambdaParameter(
11754
+ "__foreach_key__",
11755
+ parts.keyType,
11756
+ parts,
11757
+ 0
11758
+ );
11759
+ const value = variable(
11760
+ "__foreach_value__",
11761
+ parts.valueType,
11762
+ void 0,
11763
+ this.project
11764
+ );
11765
+ const alias = this.enumDictionaryKeyPointer(key, parts.keyType, parts, 0);
11766
+ const fn = {
11767
+ compilerRevision: NEOSCRIPT_COMPILER_REVISION,
11768
+ parameters: [key, value],
11769
+ instructions: [
11770
+ {
11771
+ type: "return" /* Return */,
11772
+ pointer: alias ?? {
11773
+ type: "variable" /* Variable */,
11774
+ variableId: key.id
11775
+ }
11776
+ }
11777
+ ],
11778
+ typeInfo: toWireType(parts.keyType, this.project)
11779
+ };
11780
+ return intrinsic(
11781
+ "select" /* Select */,
11782
+ { collectionPointer: dictionary.pointer, function: fn },
11783
+ { kind: "list", elementType: parts.keyType, readOnly: true }
11784
+ );
11785
+ }
11786
+ collectionLambdaParameter(name, type, collection, index) {
11787
+ const rawType = this.isEnumDictionaryKey(type, collection, index) ? { kind: "primitive", name: "string" } : type;
11788
+ return variable(name, rawType, void 0, this.project);
11789
+ }
11790
+ isEnumDictionaryKey(type, collection, index) {
11791
+ return collection.kind === "dictionary" && index === 0 && type.kind === "named" && this.project.typeById.get(type.typeId)?.kind === "enum";
11792
+ }
11793
+ enumDictionaryKeyPointer(parameter4, type, collection, index) {
11794
+ if (!this.isEnumDictionaryKey(type, collection, index)) return void 0;
11795
+ const wire = toWireType(
11796
+ {
11797
+ kind: "list",
11798
+ elementType: { kind: "primitive", name: "string" }
11799
+ },
11800
+ this.project
11801
+ );
11802
+ if (wire.type !== 6 /* List */) {
11803
+ throw new Error("Enum key alias requires a list wire type.");
11804
+ }
11805
+ return {
11806
+ type: "listLiteral" /* ListLiteral */,
11807
+ typeInfo: wire,
11808
+ entries: [
11809
+ { type: "variable" /* Variable */, variableId: parameter4.id }
11810
+ ]
11811
+ };
11812
+ }
11634
11813
  resolveCollectionLambda(ast, collection, returnType, outerScope, pos) {
11635
11814
  if (ast.kind !== "lambda") {
11636
11815
  throw new CompileError(
@@ -11658,16 +11837,30 @@ var init_strict_resolver = __esm({
11658
11837
  parameter4.pos,
11659
11838
  "lambda parameter"
11660
11839
  );
11661
- const item = variable(parameter4.name, declared, void 0, this.project);
11662
- scope.define(
11663
- scopeVariable(
11840
+ const item = this.collectionLambdaParameter(
11841
+ parameter4.name,
11842
+ declared,
11843
+ collection,
11844
+ index
11845
+ );
11846
+ const alias = this.enumDictionaryKeyPointer(
11847
+ item,
11848
+ declared,
11849
+ collection,
11850
+ index
11851
+ );
11852
+ scope.define({
11853
+ ...scopeVariable(
11664
11854
  parameter4.name,
11665
11855
  item,
11666
11856
  declared,
11667
11857
  void 0,
11668
- "runtime" /* Runtime */
11669
- )
11670
- );
11858
+ "runtime" /* Runtime */,
11859
+ void 0,
11860
+ alias ? "enumKey" : void 0
11861
+ ),
11862
+ ...alias ? { pointer: alias } : {}
11863
+ });
11671
11864
  return item;
11672
11865
  });
11673
11866
  this.functionControlBoundaries.push({
@@ -11714,16 +11907,30 @@ var init_strict_resolver = __esm({
11714
11907
  this.assertLocalNameAvailable(parameter4.name, scope, parameter4.pos);
11715
11908
  const type = parameter4.type ? this.resolveType(parameter4.type) : requiredAt(parameterTypes, index);
11716
11909
  const isValueParameter = index === valueParameterIndex;
11717
- scope.define(
11718
- scopeVariable(
11910
+ const item = this.collectionLambdaParameter(
11911
+ parameter4.name,
11912
+ type,
11913
+ collection,
11914
+ index
11915
+ );
11916
+ const alias = this.enumDictionaryKeyPointer(
11917
+ item,
11918
+ type,
11919
+ collection,
11920
+ index
11921
+ );
11922
+ scope.define({
11923
+ ...scopeVariable(
11719
11924
  parameter4.name,
11720
- variable(parameter4.name, type, void 0, this.project),
11925
+ item,
11721
11926
  type,
11722
11927
  isValueParameter ? sourceWritability : "runtime" /* Runtime */,
11723
11928
  isValueParameter ? sourceWritability : "runtime" /* Runtime */,
11724
- isValueParameter ? sourceWriteRoot : "local"
11725
- )
11726
- );
11929
+ isValueParameter ? sourceWriteRoot : "local",
11930
+ alias ? "enumKey" : void 0
11931
+ ),
11932
+ ...alias ? { pointer: alias } : {}
11933
+ });
11727
11934
  });
11728
11935
  let inferred = null;
11729
11936
  let inferredWritability = null;
@@ -14252,7 +14459,9 @@ function inferLocalType(local, snapshot) {
14252
14459
  tokens[0]?.start ?? snapshot.source.offsetAt(local.nameRange.end)
14253
14460
  );
14254
14461
  if (!local.collectionIteration) return inferred;
14255
- if (inferred.kind === "dictionary") return inferred.valueType;
14462
+ if (inferred.kind === "dictionary") {
14463
+ return local.collectionIterationKey ? inferred.keyType : inferred.valueType;
14464
+ }
14256
14465
  if (inferred.kind === "list" || inferred.kind === "set") {
14257
14466
  return inferred.elementType;
14258
14467
  }
@@ -22707,6 +22916,7 @@ function collectIdentifierReads(expression, names) {
22707
22916
  walk(statement.collection, visible);
22708
22917
  const inner = new Set(visible);
22709
22918
  inner.delete(statement.name);
22919
+ if (statement.key) inner.delete(statement.key.name);
22710
22920
  for (const bodyStatement of statement.body) {
22711
22921
  walkStatement(bodyStatement, inner);
22712
22922
  }
@@ -38029,6 +38239,12 @@ function normalizeDocumentFields(recordKind, value) {
38029
38239
  }
38030
38240
  }
38031
38241
  }
38242
+ if (recordKind === "class" && Array.isArray(normalized.genericParams)) {
38243
+ for (const parameter4 of normalized.genericParams) {
38244
+ if (!isRecord(parameter4) || !isRecord(parameter4.constraint)) continue;
38245
+ if (parameter4.constraint.kind === 0) delete parameter4.constraint.kind;
38246
+ }
38247
+ }
38032
38248
  omitRedundantDeclarationOrder(recordKind, normalized);
38033
38249
  return normalized;
38034
38250
  }
@@ -45095,6 +45311,109 @@ var init_project_manifest = __esm({
45095
45311
  }
45096
45312
  });
45097
45313
 
45314
+ // src/project-source/source-format.ts
45315
+ function quoteNeoString(value) {
45316
+ return JSON.stringify(value);
45317
+ }
45318
+ function indentNeoSource(value, spaces) {
45319
+ return indentLines(value, spaces, true);
45320
+ }
45321
+ function indentNeoSourceNonEmptyLines(value, spaces) {
45322
+ return indentLines(value, spaces, false);
45323
+ }
45324
+ function indentLines(value, spaces, indentEmptyLines) {
45325
+ const prefix = " ".repeat(spaces);
45326
+ return value.split("\n").map(
45327
+ (line) => indentEmptyLines || line.length > 0 ? `${prefix}${line}` : line
45328
+ ).join("\n");
45329
+ }
45330
+ function formatNeoNumber(value) {
45331
+ if (!Number.isFinite(value)) {
45332
+ throw new Error(`Cannot emit non-finite Neo number ${String(value)}.`);
45333
+ }
45334
+ const source = String(value);
45335
+ const match = /^(?<sign>-?)(?<integer>\d+)(?:\.(?<fraction>\d+))?[eE](?<exponent>[+-]?\d+)$/u.exec(
45336
+ source
45337
+ );
45338
+ if (match?.groups === void 0) return source;
45339
+ const sign = match.groups.sign ?? "";
45340
+ const integer3 = match.groups.integer ?? "";
45341
+ const fraction = match.groups.fraction ?? "";
45342
+ const digits = `${integer3}${fraction}`;
45343
+ const decimalIndex = integer3.length + Number(match.groups.exponent);
45344
+ if (decimalIndex <= 0) {
45345
+ return `${sign}0.${"0".repeat(-decimalIndex)}${digits}`;
45346
+ }
45347
+ if (decimalIndex >= digits.length) {
45348
+ return `${sign}${digits}${"0".repeat(decimalIndex - digits.length)}`;
45349
+ }
45350
+ return `${sign}${digits.slice(0, decimalIndex)}.${digits.slice(decimalIndex)}`;
45351
+ }
45352
+ function invariantCaseKey(value) {
45353
+ return value.toLowerCase();
45354
+ }
45355
+ var init_source_format = __esm({
45356
+ "src/project-source/source-format.ts"() {
45357
+ "use strict";
45358
+ init_machine_strings();
45359
+ }
45360
+ });
45361
+
45362
+ // src/project-source/dictionary-enum-keys.ts
45363
+ function lowerDictionaryKey(expression, keyEnum, path) {
45364
+ if (expression.kind === "litString") {
45365
+ if (keyEnum?.optionsByName.has(expression.value)) {
45366
+ throw new Error(
45367
+ `Dictionary key ${JSON.stringify(expression.value)} at ${path} names an option in enum ${JSON.stringify(keyEnum.name)}. Write .${expression.value} or its option ID.`
45368
+ );
45369
+ }
45370
+ return expression.value;
45371
+ }
45372
+ if (keyEnum === null) {
45373
+ throw new Error(`Dictionary ${path} requires string keys.`);
45374
+ }
45375
+ let optionName;
45376
+ if (expression.kind === "contextualEnum") {
45377
+ optionName = expression.name;
45378
+ } else if (expression.kind === "member" && expression.receiver.kind === "ident") {
45379
+ if (expression.receiver.name !== keyEnum.name) {
45380
+ throw new Error(
45381
+ `Dictionary key at ${path} names enum ${JSON.stringify(expression.receiver.name)}, expected ${JSON.stringify(keyEnum.name)}.`
45382
+ );
45383
+ }
45384
+ optionName = expression.name;
45385
+ } else {
45386
+ throw new Error(
45387
+ `Dictionary key at ${path} must be .Option, ${keyEnum.name}.Option, or a quoted option ID.`
45388
+ );
45389
+ }
45390
+ const optionId = keyEnum.optionsByName.get(optionName);
45391
+ if (optionId === void 0) {
45392
+ throw new Error(
45393
+ `Enum ${JSON.stringify(keyEnum.name)} has no option ${JSON.stringify(optionName)} at ${path}.`
45394
+ );
45395
+ }
45396
+ return optionId;
45397
+ }
45398
+ function emitDictionaryKey(key, options) {
45399
+ const name = options?.get(key)?.name;
45400
+ return name === void 0 ? quoteNeoString(key) : `.${name}`;
45401
+ }
45402
+ function orderedDictionaryEntries(value, options) {
45403
+ return Object.entries(value).sort(([left], [right]) => {
45404
+ const leftOrder = options?.get(left)?.order ?? Infinity;
45405
+ const rightOrder = options?.get(right)?.order ?? Infinity;
45406
+ if (leftOrder !== rightOrder) return leftOrder - rightOrder;
45407
+ return compareCodePoints(left, right);
45408
+ });
45409
+ }
45410
+ var init_dictionary_enum_keys = __esm({
45411
+ "src/project-source/dictionary-enum-keys.ts"() {
45412
+ "use strict";
45413
+ init_source_format();
45414
+ }
45415
+ });
45416
+
45098
45417
  // ../src/models/system-record-id.ts
45099
45418
  function isSystemRecordId(id2) {
45100
45419
  return id2.startsWith(SYSTEM_RECORD_ID_PREFIX2);
@@ -45153,54 +45472,6 @@ var init_declaration_path = __esm({
45153
45472
  }
45154
45473
  });
45155
45474
 
45156
- // src/project-source/source-format.ts
45157
- function quoteNeoString(value) {
45158
- return JSON.stringify(value);
45159
- }
45160
- function indentNeoSource(value, spaces) {
45161
- return indentLines(value, spaces, true);
45162
- }
45163
- function indentNeoSourceNonEmptyLines(value, spaces) {
45164
- return indentLines(value, spaces, false);
45165
- }
45166
- function indentLines(value, spaces, indentEmptyLines) {
45167
- const prefix = " ".repeat(spaces);
45168
- return value.split("\n").map(
45169
- (line) => indentEmptyLines || line.length > 0 ? `${prefix}${line}` : line
45170
- ).join("\n");
45171
- }
45172
- function formatNeoNumber(value) {
45173
- if (!Number.isFinite(value)) {
45174
- throw new Error(`Cannot emit non-finite Neo number ${String(value)}.`);
45175
- }
45176
- const source = String(value);
45177
- const match = /^(?<sign>-?)(?<integer>\d+)(?:\.(?<fraction>\d+))?[eE](?<exponent>[+-]?\d+)$/u.exec(
45178
- source
45179
- );
45180
- if (match?.groups === void 0) return source;
45181
- const sign = match.groups.sign ?? "";
45182
- const integer3 = match.groups.integer ?? "";
45183
- const fraction = match.groups.fraction ?? "";
45184
- const digits = `${integer3}${fraction}`;
45185
- const decimalIndex = integer3.length + Number(match.groups.exponent);
45186
- if (decimalIndex <= 0) {
45187
- return `${sign}0.${"0".repeat(-decimalIndex)}${digits}`;
45188
- }
45189
- if (decimalIndex >= digits.length) {
45190
- return `${sign}${digits}${"0".repeat(decimalIndex - digits.length)}`;
45191
- }
45192
- return `${sign}${digits.slice(0, decimalIndex)}.${digits.slice(decimalIndex)}`;
45193
- }
45194
- function invariantCaseKey(value) {
45195
- return value.toLowerCase();
45196
- }
45197
- var init_source_format = __esm({
45198
- "src/project-source/source-format.ts"() {
45199
- "use strict";
45200
- init_machine_strings();
45201
- }
45202
- });
45203
-
45204
45475
  // src/project-source/ui-action-source.ts
45205
45476
  function isCompleteUIAction(rawAction) {
45206
45477
  const action = object(rawAction);
@@ -52927,7 +53198,7 @@ function assertReadOnlyMembersValid(document) {
52927
53198
  `Read-only member "${member.name}" (${member.id}) must declare Immutable storage; ${ownerContext}.`
52928
53199
  );
52929
53200
  }
52930
- if (isAbstractMember(member) !== true && resolved.kind !== 21 /* Generic */ && resolved.defaultValue === void 0) {
53201
+ if (isAbstractMember(resolved) !== true && resolved.kind !== 21 /* Generic */ && resolved.defaultValue === void 0) {
52931
53202
  throw new Error(
52932
53203
  `Read-only member "${member.name}" (${member.id}) requires an explicit defaultValue; ${ownerContext}.`
52933
53204
  );
@@ -52967,7 +53238,7 @@ function assertReadOnlyMembersValid(document) {
52967
53238
  `Read-only member "${member.name}" (${member.id}) must be value-bearing in every closed Generic placement; ${ownerContext}.`
52968
53239
  );
52969
53240
  }
52970
- if (isAbstractMember(member) === true) continue;
53241
+ if (isAbstractMember(resolved) === true) continue;
52971
53242
  if (effective.defaultValue == null) {
52972
53243
  throw new Error(
52973
53244
  `Read-only member "${member.name}" (${member.id}) requires an explicit field defaultValue in every closed Generic placement; ${ownerContext}.`
@@ -52984,7 +53255,7 @@ function assertReadOnlyMembersValid(document) {
52984
53255
  );
52985
53256
  }
52986
53257
  }
52987
- if (isAbstractMember(member) === true) continue;
53258
+ if (isAbstractMember(resolved) === true) continue;
52988
53259
  assertOwnedSchemaIsImmutable({
52989
53260
  member,
52990
53261
  memberId: member.id,
@@ -53209,6 +53480,25 @@ function virtualValueId(instanceRootId, sourceIdentity3) {
53209
53480
  )
53210
53481
  );
53211
53482
  }
53483
+ function virtualSourceIdentityHead(sourceIdentity3) {
53484
+ const pathStart = sourceIdentity3.indexOf(":$");
53485
+ return pathStart < 0 ? sourceIdentity3 : sourceIdentity3.slice(0, pathStart);
53486
+ }
53487
+ function hasPendingVirtualSourceIdentity(sourceIdentity3) {
53488
+ const head = virtualSourceIdentityHead(sourceIdentity3);
53489
+ return head.startsWith("path:__pending__:") || head.startsWith("__pending__:");
53490
+ }
53491
+ function rewriteVirtualSourceIdentity(sourceIdentity3, rewriteId) {
53492
+ const head = virtualSourceIdentityHead(sourceIdentity3);
53493
+ const path = sourceIdentity3.slice(head.length);
53494
+ if (head.startsWith("path:__pending__:")) {
53495
+ return `path:${rewriteId(head.slice("path:".length))}${path}`;
53496
+ }
53497
+ if (head.startsWith("__pending__:")) {
53498
+ return `${rewriteId(head)}${path}`;
53499
+ }
53500
+ return sourceIdentity3;
53501
+ }
53212
53502
  function pendingVirtualValueId(pendingInstanceRootId, sourceIdentity3) {
53213
53503
  return `${PENDING_VIRTUAL_VALUE_PREFIX}${encodeURIComponent(pendingInstanceRootId)}:${encodeURIComponent(sourceIdentity3)}`;
53214
53504
  }
@@ -57815,6 +58105,7 @@ function emitProjectSourcesV4(manifest, options = {}) {
57815
58105
  classes: new Map(manifest.classes.map((entry) => [entry.id, entry])),
57816
58106
  interfaces: new Map(manifest.interfaces.map((entry) => [entry.id, entry])),
57817
58107
  enums: new Map(manifest.enums.map((entry) => [entry.id, entry])),
58108
+ dictionaryKeyOptions: /* @__PURE__ */ new Map(),
57818
58109
  members: new Map(manifest.members.map((entry) => [entry.id, entry])),
57819
58110
  constructorsById: new Map(
57820
58111
  manifest.constructors.map((entry) => [entry.id, entry])
@@ -58833,6 +59124,18 @@ function initDefaultSource(member) {
58833
59124
  if (!("init" in value)) return void 0;
58834
59125
  return value.init.code;
58835
59126
  }
59127
+ function dictionaryOptions(context, enumId) {
59128
+ const cached = context.dictionaryKeyOptions.get(enumId);
59129
+ if (cached !== void 0) return cached;
59130
+ const result = new Map(
59131
+ required(context.enums, enumId, "enum").options.map((option, order) => [
59132
+ option.id,
59133
+ { name: option.name, order }
59134
+ ])
59135
+ );
59136
+ context.dictionaryKeyOptions.set(enumId, result);
59137
+ return result;
59138
+ }
58836
59139
  function renderDefaultValue(context, member, wrapper, enclosingClassId) {
58837
59140
  const value = wrapper.value;
58838
59141
  if (value === null) return "null";
@@ -58861,8 +59164,10 @@ function renderDefaultValue(context, member, wrapper, enclosingClassId) {
58861
59164
  member.entryMemberId,
58862
59165
  "dictionary entry"
58863
59166
  );
58864
- return `{ ${Object.entries(value).map(
58865
- ([key, item]) => `${quote(key)}: ${renderNestedValue(context, entry, item, enclosingClassId)}`
59167
+ const keyOptions = member.key.kind === "enum" ? dictionaryOptions(context, member.key.enumId) : null;
59168
+ const entries = keyOptions ? orderedDictionaryEntries(value, keyOptions) : Object.entries(value);
59169
+ return `{ ${entries.map(
59170
+ ([key, item]) => `${emitDictionaryKey(key, keyOptions)}: ${renderNestedValue(context, entry, item, enclosingClassId)}`
58866
59171
  ).join(", ")} }`;
58867
59172
  }
58868
59173
  if (member.kind === "class" && isObject3(value)) {
@@ -59478,6 +59783,7 @@ var SPECIALIZED_RELATION_PROPERTIES;
59478
59783
  var init_emitter = __esm({
59479
59784
  "src/project-source/emitter.ts"() {
59480
59785
  "use strict";
59786
+ init_dictionary_enum_keys();
59481
59787
  init_declaration_path();
59482
59788
  init_src();
59483
59789
  init_source_format();
@@ -68646,6 +68952,76 @@ var init_unattributable_reads = __esm({
68646
68952
  }
68647
68953
  });
68648
68954
 
68955
+ // ../src/runtime/neoscript/NSGetterRuntimeError.ts
68956
+ var NSGetterRuntimeError, UncompiledInitializerRuntimeError;
68957
+ var init_NSGetterRuntimeError = __esm({
68958
+ "../src/runtime/neoscript/NSGetterRuntimeError.ts"() {
68959
+ "use strict";
68960
+ NSGetterRuntimeError = class extends Error {
68961
+ constructor(message, options) {
68962
+ super(message, options);
68963
+ this.name = "NSGetterRuntimeError";
68964
+ }
68965
+ };
68966
+ UncompiledInitializerRuntimeError = class extends NSGetterRuntimeError {
68967
+ constructor(memberId, memberName, initializer = null, valueId = null) {
68968
+ super(
68969
+ `Initializer for '${memberName}' has no compiled body; push the project so the server compiles it.`
68970
+ );
68971
+ this.memberId = memberId;
68972
+ this.initializer = initializer;
68973
+ this.valueId = valueId;
68974
+ this.name = "UncompiledInitializerRuntimeError";
68975
+ }
68976
+ memberId;
68977
+ initializer;
68978
+ valueId;
68979
+ };
68980
+ }
68981
+ });
68982
+
68983
+ // ../src/runtime/neoscript/initializer-dependencies.ts
68984
+ function materializeInitializerDependencies(pending, materialize) {
68985
+ const active = /* @__PURE__ */ new Set();
68986
+ for (const rootId of pending) {
68987
+ const stack = [rootId];
68988
+ active.add(rootId);
68989
+ while (stack.length > 0) {
68990
+ const valueId = stack[stack.length - 1];
68991
+ try {
68992
+ materialize(valueId);
68993
+ pending.delete(valueId);
68994
+ active.delete(valueId);
68995
+ stack.pop();
68996
+ } catch (error) {
68997
+ if (!(error instanceof PendingInitializerDependency)) throw error;
68998
+ if (!pending.has(error.valueId)) throw error;
68999
+ if (active.has(error.valueId)) {
69000
+ throw new Error(
69001
+ `Initializer dependency cycle: ${[...stack, error.valueId].join(" -> ")}.`
69002
+ );
69003
+ }
69004
+ active.add(error.valueId);
69005
+ stack.push(error.valueId);
69006
+ }
69007
+ }
69008
+ }
69009
+ }
69010
+ var PendingInitializerDependency;
69011
+ var init_initializer_dependencies = __esm({
69012
+ "../src/runtime/neoscript/initializer-dependencies.ts"() {
69013
+ "use strict";
69014
+ init_NSGetterRuntimeError();
69015
+ PendingInitializerDependency = class extends NSGetterRuntimeError {
69016
+ constructor(valueId) {
69017
+ super(`Initializer dependency "${valueId}" has not been materialized.`);
69018
+ this.valueId = valueId;
69019
+ }
69020
+ valueId;
69021
+ };
69022
+ }
69023
+ });
69024
+
68649
69025
  // ../src/runtime/neoscript/cell-pattern.ts
68650
69026
  function integer2(value, name, minimum = -2147483648) {
68651
69027
  if (typeof value !== "number" || !Number.isInteger(value)) {
@@ -70581,37 +70957,9 @@ var init_NeoScriptScope = __esm({
70581
70957
  }
70582
70958
  });
70583
70959
 
70584
- // ../src/runtime/neoscript/NSGetterRuntimeError.ts
70585
- var NSGetterRuntimeError, UncompiledInitializerRuntimeError;
70586
- var init_NSGetterRuntimeError = __esm({
70587
- "../src/runtime/neoscript/NSGetterRuntimeError.ts"() {
70588
- "use strict";
70589
- NSGetterRuntimeError = class extends Error {
70590
- constructor(message, options) {
70591
- super(message, options);
70592
- this.name = "NSGetterRuntimeError";
70593
- }
70594
- };
70595
- UncompiledInitializerRuntimeError = class extends NSGetterRuntimeError {
70596
- constructor(memberId, memberName, initializer = null, valueId = null) {
70597
- super(
70598
- `Initializer for '${memberName}' has no compiled body; push the project so the server compiles it.`
70599
- );
70600
- this.memberId = memberId;
70601
- this.initializer = initializer;
70602
- this.valueId = valueId;
70603
- this.name = "UncompiledInitializerRuntimeError";
70604
- }
70605
- memberId;
70606
- initializer;
70607
- valueId;
70608
- };
70609
- }
70610
- });
70611
-
70612
70960
  // ../src/runtime/neoscript/evaluateNSGetter.ts
70613
70961
  function isCatchableNeoScriptRuntimeError(error) {
70614
- return error instanceof NSGetterRuntimeError && !(error instanceof UncompiledInitializerRuntimeError) && !(error instanceof NonCatchableNSGetterRuntimeError);
70962
+ return error instanceof NSGetterRuntimeError && !(error instanceof UncompiledInitializerRuntimeError) && !(error instanceof PendingInitializerDependency) && !(error instanceof NonCatchableNSGetterRuntimeError);
70615
70963
  }
70616
70964
  function makeUnindexedEvaluatorLookups(members, storedValues) {
70617
70965
  const values = expandPackedValueRows(storedValues);
@@ -73910,7 +74258,7 @@ function evalStaticMember(memberId, ctx) {
73910
74258
  `Static member '${member.name}' is bound to missing value '${targetId}'.`
73911
74259
  );
73912
74260
  }
73913
- return shouldUnwrapSingleLookupValue(member) ? unwrapSingleLookupValue(row.value, ctx) : resolveLocalizedRowValueForMember(row, member, ctx);
74261
+ return shouldUnwrapSingleLookupValue(member) ? unwrapSingleLookupValue(readRowValue(row, ctx), ctx) : resolveLocalizedRowValueForMember(row, member, ctx);
73914
74262
  }
73915
74263
  function evalPointer(pointer, scope, ctx) {
73916
74264
  switch (pointer.type) {
@@ -73950,7 +74298,7 @@ function evalPointer(pointer, scope, ctx) {
73950
74298
  `Missing value reference: ${pointer.valueId}`
73951
74299
  );
73952
74300
  }
73953
- return row.value;
74301
+ return readRowValue(row, ctx);
73954
74302
  }
73955
74303
  case "variant" /* variant */:
73956
74304
  return {
@@ -74328,7 +74676,7 @@ function invokeDelegateValue(value, args, ctx, callSiteId, ownerReceiver) {
74328
74676
  `NeoDelegate target '${member.name}' has missing receiver value '${value.valueId}'.`
74329
74677
  );
74330
74678
  }
74331
- receiver = row.value;
74679
+ receiver = readRowValue(row, ctx);
74332
74680
  } else if (ownerReceiver !== null && ownerReceiver !== void 0) {
74333
74681
  receiver = listenerReceiverOnOwner(member.id, ownerReceiver, ctx);
74334
74682
  }
@@ -75363,6 +75711,20 @@ function dispatchSchemaMember(receiver, schemaKey, ctx) {
75363
75711
  if (typeof receiver !== "object" || receiver === null) {
75364
75712
  return { kind: "no-info", matchedMember: false };
75365
75713
  }
75714
+ if (ctx.vm.databaseVM?.onInitializerRead !== void 0 && receiver === ctx.rootValue) {
75715
+ const root = PROJECT_ROOTS.find((root2) => root2.key === schemaKey);
75716
+ if (root !== void 0) {
75717
+ const memberId = ctx.vm.project[root.projectField];
75718
+ let bindings;
75719
+ if (root.storage === 2 /* Save */)
75720
+ bindings = ctx.__saveStaticBindings;
75721
+ if (root.storage === 3 /* Session */)
75722
+ bindings = ctx.__sessionStaticBindings;
75723
+ const targetId = bindings?.has(memberId) ? bindings.get(memberId) : evalMemberById(ctx.vm, memberId)?.valueId;
75724
+ if (typeof targetId === "string")
75725
+ ctx.vm.databaseVM.onInitializerRead(targetId);
75726
+ }
75727
+ }
75366
75728
  const member = resolveRuntimeSchemaMember(receiver, schemaKey, ctx);
75367
75729
  if (!member) return { kind: "no-info", matchedMember: false };
75368
75730
  if (member.kind === 10 /* NSProperty */) {
@@ -75688,20 +76050,27 @@ function unwrapSingleLookupValue(value, ctx) {
75688
76050
  ctx.__valueOverlay
75689
76051
  );
75690
76052
  if (next) {
75691
- return next.value;
76053
+ return readRowValue(next, ctx);
75692
76054
  }
75693
76055
  }
75694
76056
  return value;
75695
76057
  }
76058
+ function readRowValue(row, ctx) {
76059
+ const onInitializerRead = ctx.vm.databaseVM?.onInitializerRead;
76060
+ if (onInitializerRead !== void 0 && isInitValueContent(row)) {
76061
+ onInitializerRead(row.id);
76062
+ }
76063
+ return row.value;
76064
+ }
75696
76065
  function resolveLocalizedRowValue(row, ctx) {
75697
- const value = row.value;
76066
+ const value = readRowValue(row, ctx);
75698
76067
  if (typeof value !== "string") return value;
75699
76068
  const member = memberForValueRow(row, ctx);
75700
76069
  if (member === null) return value;
75701
76070
  return resolveLocalizedRowValueForMember(row, member, ctx);
75702
76071
  }
75703
76072
  function resolveLocalizedRowValueForMember(row, member, ctx) {
75704
- const value = row.value;
76073
+ const value = readRowValue(row, ctx);
75705
76074
  if (typeof value !== "string") return value;
75706
76075
  if (!isMemberString(member)) return value;
75707
76076
  if (isLocalizedStringMember(member) === false) return value;
@@ -76003,7 +76372,7 @@ function evaluateSystemNative(memberId, receiver, args, ctx) {
76003
76372
  `Tile placement '${tile.placementValueId}' is missing.`
76004
76373
  );
76005
76374
  }
76006
- return { handled: true, value: row.value };
76375
+ return { handled: true, value: readRowValue(row, ctx) };
76007
76376
  }
76008
76377
  return evaluateCellPatternNative(memberId, receiver, args, {
76009
76378
  readPattern: (value) => readCellPattern(value, ctx),
@@ -78813,7 +79182,7 @@ function resolveVariantGraph(selection2, ctx) {
78813
79182
  `Variant '${record6.name}' has no root value row '${record6.valueId}'.`
78814
79183
  );
78815
79184
  }
78816
- const root = row.value;
79185
+ const root = readRowValue(row, ctx);
78817
79186
  if (typeof root !== "object" || root === null || Array.isArray(root)) {
78818
79187
  throw new NSGetterRuntimeError(
78819
79188
  `Variant '${record6.name}' root row is not a class record.`
@@ -78886,19 +79255,21 @@ function resolveVariantRowParameter(args) {
78886
79255
  ctx.__runtimeSessionValues,
78887
79256
  ctx.__valueOverlay
78888
79257
  );
78889
- const isOrderedEntry = Array.isArray(collection?.value) ? collection.value.includes(rowId) : false;
79258
+ const collectionValue = collection === null ? null : readRowValue(collection, ctx);
79259
+ const isOrderedEntry = Array.isArray(collectionValue) ? collectionValue.includes(rowId) : false;
78890
79260
  const isUnorderedEntry = row.containerId === binding.collectionValueId;
78891
79261
  if (!isOrderedEntry && !isUnorderedEntry) {
78892
79262
  throw new NSGetterRuntimeError(
78893
79263
  `Lookup variant '${graph.name}' row '${rowId}' is not an entry of collection '${binding.collectionValueId}'.`
78894
79264
  );
78895
79265
  }
78896
- if (explicitPointer !== void 0 && rowValue !== row.value) {
79266
+ const resolvedRowValue = readRowValue(row, ctx);
79267
+ if (explicitPointer !== void 0 && rowValue !== resolvedRowValue) {
78897
79268
  throw new NSGetterRuntimeError(
78898
79269
  `Lookup variant '${graph.name}' received a value that does not resolve to bound row '${rowId}'.`
78899
79270
  );
78900
79271
  }
78901
- return [row.value];
79272
+ return [resolvedRowValue];
78902
79273
  }
78903
79274
  function invokeVariantClosure(args) {
78904
79275
  const { closureValueId, ctx, label, lexicalThis, parameters } = args;
@@ -80306,7 +80677,7 @@ function constructorCollectionEntryValue(value, ctx, resolveStoredId) {
80306
80677
  ctx.__runtimeSessionValues,
80307
80678
  ctx.__valueOverlay
80308
80679
  );
80309
- return row === null ? value : row.value;
80680
+ return row === null ? value : readRowValue(row, ctx);
80310
80681
  }
80311
80682
  function retainOnlyCreatedRowsReachableFrom(rootId, createdValues, ctx) {
80312
80683
  const byId = new Map(createdValues.map((row) => [row.id, row]));
@@ -80716,14 +81087,16 @@ function readOptionalMember(receiver, key, ctx) {
80716
81087
  const record6 = receiver;
80717
81088
  if (!Object.prototype.hasOwnProperty.call(record6, key)) return null;
80718
81089
  return resolveValueIfId(record6[key], ctx);
80719
- } catch {
81090
+ } catch (error) {
81091
+ if (error instanceof PendingInitializerDependency) throw error;
80720
81092
  return null;
80721
81093
  }
80722
81094
  }
80723
81095
  function collectionEntriesOrEmpty(value, ctx) {
80724
81096
  try {
80725
81097
  return collectionEntries(value, ctx);
80726
- } catch {
81098
+ } catch (error) {
81099
+ if (error instanceof PendingInitializerDependency) throw error;
80727
81100
  return [];
80728
81101
  }
80729
81102
  }
@@ -80816,6 +81189,8 @@ var DELEGATE_LEXICAL_THIS, DELEGATE_LEXICAL_ROOT, NonCatchableNSGetterRuntimeErr
80816
81189
  var init_evaluateNSGetter = __esm({
80817
81190
  "../src/runtime/neoscript/evaluateNSGetter.ts"() {
80818
81191
  "use strict";
81192
+ init_project_root_members();
81193
+ init_initializer_dependencies();
80819
81194
  init_unattributable_reads();
80820
81195
  init_value_row_owner_members();
80821
81196
  init_src();
@@ -84137,7 +84512,8 @@ function createHeadlessVirtualInstanceResolver(args) {
84137
84512
  readsByRootId.set(rootId, reads);
84138
84513
  remember(graph, rows);
84139
84514
  return rows;
84140
- } catch {
84515
+ } catch (error) {
84516
+ if (error instanceof PendingInitializerDependency) throw error;
84141
84517
  failedRootIds.add(rootId);
84142
84518
  return emptyRows;
84143
84519
  } finally {
@@ -84253,6 +84629,7 @@ var KEPT_ROW_SAMPLE_LIMIT, CORPUS_SCANNING_MEMBER_KINDS, VirtualExpansionUnsuppo
84253
84629
  var init_virtual_instance_graph = __esm({
84254
84630
  "../src/runtime/virtual-instance-graph.ts"() {
84255
84631
  "use strict";
84632
+ init_initializer_dependencies();
84256
84633
  init_constructor_argument_ownership();
84257
84634
  init_classes();
84258
84635
  init_constructor_parameter_settlement();
@@ -84320,6 +84697,7 @@ function initializerEvaluatorLookups(document, readTracking) {
84320
84697
  const lookups2 = {
84321
84698
  memberById: (id2) => databaseVM.memberById(id2),
84322
84699
  valueById: (id2) => databaseVM.valueById(id2),
84700
+ onInitializerRead: databaseVM.onInitializerRead,
84323
84701
  localizedTextById: (id2) => databaseVM.localizedTextById?.(id2) ?? null,
84324
84702
  ...databaseVM.hasStoredValueId === void 0 ? {} : {
84325
84703
  hasStoredValueId: (id2) => databaseVM.hasStoredValueId?.(id2) ?? false
@@ -84475,7 +84853,7 @@ function indexedInitializerEvaluatorLookups(document, key, revision) {
84475
84853
  });
84476
84854
  return lookups;
84477
84855
  }
84478
- function createInitializerMaterializationBatch(authoredDocument) {
84856
+ function createInitializerMaterializationBatch(authoredDocument, pendingInitializerIds) {
84479
84857
  const indexed = createInitializerBatchLookups(authoredDocument);
84480
84858
  const unorderedListEntryIds2 = indexed.snapshot().unorderedListEntryIds;
84481
84859
  let materializedIndex;
@@ -84526,6 +84904,9 @@ function createInitializerMaterializationBatch(authoredDocument) {
84526
84904
  globalReads.delete(entry);
84527
84905
  };
84528
84906
  return {
84907
+ get valuesById() {
84908
+ return indexed.valuesById;
84909
+ },
84529
84910
  upsert(rows) {
84530
84911
  const previousRows = [];
84531
84912
  const touched = /* @__PURE__ */ new Set();
@@ -84600,6 +84981,12 @@ function createInitializerMaterializationBatch(authoredDocument) {
84600
84981
  });
84601
84982
  const lookups = {
84602
84983
  ...base,
84984
+ ...pendingInitializerIds === void 0 ? {} : {
84985
+ onInitializerRead: (id2) => {
84986
+ if (pendingInitializerIds.has(id2))
84987
+ throw new PendingInitializerDependency(id2);
84988
+ }
84989
+ },
84603
84990
  valueById: (id2) => base.valueById(id2) ?? expandedById.get(id2) ?? virtual().valueById(id2),
84604
84991
  rowForValueReference: (value) => base.rowForValueReference(value) ?? expandedByReference.get(value) ?? virtual().rowForValueReference(value),
84605
84992
  virtualInstanceRowsForValue: (id2) => {
@@ -84666,7 +85053,8 @@ function buildInitializerRootValueWithLookups(document, lookups, tracking) {
84666
85053
  continue;
84667
85054
  }
84668
85055
  tracking?.valueDependencies?.add(targetId);
84669
- rootValue[root.key] = lookups.valueById(targetId)?.value ?? null;
85056
+ const row = lookups.valueById(targetId);
85057
+ rootValue[root.key] = row?.value ?? null;
84670
85058
  }
84671
85059
  return rootValue;
84672
85060
  }
@@ -84823,6 +85211,7 @@ var evaluatorLookupsByDocument, headlessResolversByLookupKey, indexedEvaluatorLo
84823
85211
  var init_evaluateInitializer = __esm({
84824
85212
  "../src/runtime/neoscript/evaluateInitializer.ts"() {
84825
85213
  "use strict";
85214
+ init_initializer_dependencies();
84826
85215
  init_deep_clone_plain_data();
84827
85216
  init_members();
84828
85217
  init_instance_provenance();
@@ -93044,7 +93433,9 @@ function validateWorldPlacementSidecars(args) {
93044
93433
  `Placement value "${args.placement.id}" under layer link "${args.linkValueId}" must store a class record.`
93045
93434
  );
93046
93435
  }
93047
- const assetClassId = args.isTile ? requiredValueClassId(args.placement, "tile") : optionalNonEmptyString(record6.assetClassId);
93436
+ const hasObjectSidecar = !args.isTile && WORLD_PLACEMENT_SIDECAR_KEYS.some((key) => Object.hasOwn(record6, key));
93437
+ const objectClassId = hasObjectSidecar ? record6.assetClassId : args.placement.classId;
93438
+ const assetClassId = args.isTile ? requiredValueClassId(args.placement, "tile") : optionalNonEmptyString(objectClassId);
93048
93439
  if (assetClassId === null) {
93049
93440
  throw new Error(
93050
93441
  `Class-backed placement value "${args.placement.id}" is missing assetClassId.`
@@ -93093,10 +93484,10 @@ function validateWorldPlacementSidecars(args) {
93093
93484
  assetClassId,
93094
93485
  placementId: args.placement.id,
93095
93486
  variantId: optionalNonEmptyString(
93096
- args.isTile ? getField(args.placement, "instanceVariantId") : record6.variantId
93487
+ args.isTile || !hasObjectSidecar ? getField(args.placement, "instanceVariantId") : record6.variantId
93097
93488
  ),
93098
93489
  rowValueId: optionalNonEmptyString(
93099
- args.isTile ? getField(args.placement, "instanceVariantRowValueId") : record6.rowValueId
93490
+ args.isTile || !hasObjectSidecar ? getField(args.placement, "instanceVariantRowValueId") : record6.rowValueId
93100
93491
  ),
93101
93492
  context: args.context
93102
93493
  });
@@ -98167,37 +98558,49 @@ function materializePreparedInstanceInitializers(args) {
98167
98558
  materializationScope.document.localizedTexts.map((text) => text.id)
98168
98559
  );
98169
98560
  const replayOnlyIndexes = [];
98561
+ const pendingSites = /* @__PURE__ */ new Map();
98170
98562
  for (const [valueId, site] of sites) {
98171
98563
  const existingRoot = existingValueById.get(valueId);
98172
- const existingConstructedRoot = existingRoot !== void 0 && isLiteralValueContent(existingRoot) && (typeof existingRoot.classId === "string" || existingRoot.constructorArgs !== void 0 && existingRoot.constructorArgs !== null);
98173
- if (rootKinds.get(valueId) === "declaration" && !existingConstructedRoot) {
98564
+ const existingConstructedRoot = existingRoot !== void 0 && isLiteralValueContent(existingRoot) && (typeof existingRoot.classId === "string" || existingRoot.constructorArgs !== void 0 && existingRoot.constructorArgs !== null) ? existingRoot : void 0;
98565
+ if (rootKinds.get(valueId) === "declaration" && !existingConstructedRoot)
98174
98566
  continue;
98175
- }
98567
+ pendingSites.set(valueId, { ...site, existingConstructedRoot });
98568
+ }
98569
+ const pendingInitializerIds = new Set(pendingSites.keys());
98570
+ if (pendingInitializerIds.size === 0) return;
98571
+ const batch = createInitializerMaterializationBatch(
98572
+ materializationScope.document,
98573
+ pendingInitializerIds
98574
+ );
98575
+ materializeInitializerDependencies(pendingInitializerIds, (valueId) => {
98576
+ const site = pendingSites.get(valueId);
98577
+ const existingConstructedRoot = site.existingConstructedRoot;
98176
98578
  const member = owners.get(valueId);
98177
98579
  if (member === void 0) {
98178
98580
  throw new Error(
98179
98581
  `Value "${valueId}" carries an initializer but no ownership path resolves its declared member.`
98180
98582
  );
98181
98583
  }
98584
+ const currentDocument = batch.document();
98182
98585
  const materialized = materializeInitializerValue2({
98183
98586
  // Every site that survives the declaration-default guard is source for
98184
98587
  // a persisted instance construction. The trusted replay mode both
98185
98588
  // admits Immutable storage and installs the concrete generic slot; the
98186
98589
  // CLI uses the same mode on the first push, so it cannot be conditional
98187
98590
  // on a literal row already existing.
98188
- document: materializationScope.document,
98591
+ document: currentDocument,
98189
98592
  member,
98190
98593
  row: site.row,
98191
98594
  storedConstructionReplay: true
98192
98595
  });
98193
- if (existingConstructedRoot) {
98194
- if (!isLiteralValueContent(materialized.root) || existingRoot.classId !== materialized.root.classId || !replayedCreationDataMatches({
98596
+ if (existingConstructedRoot !== void 0) {
98597
+ if (!isLiteralValueContent(materialized.root) || existingConstructedRoot.classId !== materialized.root.classId || !replayedCreationDataMatches({
98195
98598
  // The synthetic variant binding members are part of the ownership
98196
98599
  // scope that compiled and evaluated this initializer. Stored replay
98197
98600
  // closes its generic slot from the same ephemeral member id, so its
98198
98601
  // expansion must read that scoped document too.
98199
98602
  currentReader: requireCurrentReader(),
98200
- currentRoot: existingRoot,
98603
+ currentRoot: existingConstructedRoot,
98201
98604
  rootMember: member,
98202
98605
  replayRoot: materialized.root,
98203
98606
  replayCreated: materialized.createdValues
@@ -98207,10 +98610,11 @@ function materializePreparedInstanceInitializers(args) {
98207
98610
  );
98208
98611
  }
98209
98612
  replayOnlyIndexes.push(site.index);
98210
- continue;
98613
+ batch.upsert([existingConstructedRoot]);
98614
+ return;
98211
98615
  }
98212
98616
  const baseline = materializeInitializerValue2({
98213
- document: materializationScope.document,
98617
+ document: currentDocument,
98214
98618
  member,
98215
98619
  row: {
98216
98620
  ...site.row,
@@ -98221,7 +98625,7 @@ function materializePreparedInstanceInitializers(args) {
98221
98625
  });
98222
98626
  const sparse2 = sparsifyConstructedInstance({
98223
98627
  localizedTextIds,
98224
- document: materializationScope.document,
98628
+ document: currentDocument,
98225
98629
  rootMember: member,
98226
98630
  constructed: {
98227
98631
  root: materialized.root,
@@ -98237,7 +98641,7 @@ function materializePreparedInstanceInitializers(args) {
98237
98641
  pinnedRootSchemaKeys: materialized.pinnedRootSchemaKeys
98238
98642
  });
98239
98643
  const original = args.prepared[site.index];
98240
- if (original === void 0) continue;
98644
+ if (original === void 0) return;
98241
98645
  args.prepared[site.index] = {
98242
98646
  ...original,
98243
98647
  nextData: sparse2.root
@@ -98278,7 +98682,8 @@ function materializePreparedInstanceInitializers(args) {
98278
98682
  });
98279
98683
  existingValueById.set(created.id, created);
98280
98684
  }
98281
- }
98685
+ batch.upsert([sparse2.root, ...sparse2.createdChildren]);
98686
+ });
98282
98687
  for (const index of replayOnlyIndexes.sort((left, right) => right - left)) {
98283
98688
  args.prepared.splice(index, 1);
98284
98689
  }
@@ -101481,6 +101886,7 @@ var init_project_version_schema_commit = __esm({
101481
101886
  init_variants2();
101482
101887
  init_effective_value_reader();
101483
101888
  init_materialize_values();
101889
+ init_initializer_dependencies();
101484
101890
  init_neoscript2();
101485
101891
  init_evaluateInitializer();
101486
101892
  init_virtual_instance_graph();
@@ -101617,6 +102023,7 @@ var init_animation_clips = __esm({
101617
102023
  "../src/models/animation/animation-clips.ts"() {
101618
102024
  "use strict";
101619
102025
  init_inheritance();
102026
+ init_read_class_member();
101620
102027
  init_generics();
101621
102028
  init_world_system_classes();
101622
102029
  init_member_kinds();
@@ -102635,14 +103042,7 @@ var init_animation_clips = __esm({
102635
103042
  * when it is dangling, then the member default, then the retained value row.
102636
103043
  */
102637
103044
  listFieldIds(parent, field) {
102638
- const mapped = isRecord6(parent.value) ? parent.value[field.schemaKey] : null;
102639
- if (typeof mapped === "string") {
102640
- return this.valueById.get(mapped)?.value;
102641
- }
102642
- if (field.member.defaultValue !== void 0) {
102643
- return field.member.defaultValue.value;
102644
- }
102645
- return typeof field.member.valueId === "string" ? this.valueById.get(field.member.valueId)?.value : void 0;
103045
+ return this.fieldValue(parent, field);
102646
103046
  }
102647
103047
  /** Class a list's rows carry when a row omits its own `classId`. */
102648
103048
  listEntryClassId(member) {
@@ -102692,11 +103092,21 @@ var init_animation_clips = __esm({
102692
103092
  }
102693
103093
  scalarField(parent, classId, memberId) {
102694
103094
  const field = this.requireField(classId, memberId, `Class "${classId}"`);
102695
- const mapped = isRecord6(parent.value) ? parent.value[field.schemaKey] : null;
102696
- if (typeof mapped === "string") {
102697
- return this.valueById.get(mapped)?.value;
103095
+ return this.fieldValue(parent, field);
103096
+ }
103097
+ fieldValue(parent, field) {
103098
+ const slot = readClassMember({
103099
+ member: field.member,
103100
+ schemaKey: field.schemaKey,
103101
+ record: isRecord6(parent.value) ? parent.value : {},
103102
+ expandedRecord: () => null,
103103
+ mode: "declaration"
103104
+ });
103105
+ if (slot.kind === "declaration") return slot.content.value;
103106
+ if (slot.kind === "value") {
103107
+ return typeof slot.value === "string" ? this.valueById.get(slot.value)?.value : slot.value;
102698
103108
  }
102699
- return field.member.defaultValue?.value;
103109
+ return typeof field.member.valueId === "string" ? this.valueById.get(field.member.valueId)?.value : void 0;
102700
103110
  }
102701
103111
  requireNodeClassId(node, expectedWorldKind) {
102702
103112
  if (typeof node.classId !== "string" || !this.classHasWorldKind(node.classId, expectedWorldKind)) {
@@ -102735,7 +103145,13 @@ var init_animation_clips = __esm({
102735
103145
  );
102736
103146
  if (entry === void 0) return null;
102737
103147
  const member = this.memberById.get(entry.memberId);
102738
- return member === void 0 ? null : { ...entry, member };
103148
+ return member === void 0 ? null : {
103149
+ ...entry,
103150
+ member: {
103151
+ ...member,
103152
+ ...resolveMember2(member, this.document.members)
103153
+ }
103154
+ };
102739
103155
  }
102740
103156
  requireField(classId, memberId, label) {
102741
103157
  const field = this.field(classId, memberId);
@@ -104334,7 +104750,7 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
104334
104750
  `Read-only member "${member.name}" (${member.id}) must declare Immutable storage; ${ownerLabel}.`
104335
104751
  );
104336
104752
  }
104337
- if (!isAbstractMember(member) && resolved.kind !== 21 && (resolved.defaultValue === void 0 || resolved.defaultValue === null)) {
104753
+ if (!isAbstractMember(resolved) && resolved.kind !== 21 && (resolved.defaultValue === void 0 || resolved.defaultValue === null)) {
104338
104754
  throw new Error(
104339
104755
  `Read-only member "${member.name}" (${member.id}) requires an explicit defaultValue; ${ownerLabel}.`
104340
104756
  );
@@ -104398,7 +104814,7 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
104398
104814
  `Read-only member "${member.name}" (${member.id}) must be value-bearing in every closed Generic placement; ${ownerLabel}.`
104399
104815
  );
104400
104816
  }
104401
- if (isAbstractMember(member)) return;
104817
+ if (isAbstractMember(inherited)) return;
104402
104818
  if (owned.defaultValue === void 0 || owned.defaultValue === null) {
104403
104819
  throw new Error(
104404
104820
  `Read-only member "${member.name}" (${member.id}) requires an explicit defaultValue from every closed Generic binding; ${ownerLabel}.`
@@ -104416,7 +104832,7 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
104416
104832
  }
104417
104833
  }
104418
104834
  }
104419
- if (rawOwned.id === member.id && isAbstractMember(member)) return;
104835
+ if (rawOwned.id === member.id && isAbstractMember(inherited)) return;
104420
104836
  if (owned.storage === 2 /* Save */ || owned.storage === 3 /* Session */ || owned.storage === 4 /* Writable */) {
104421
104837
  throw new Error(
104422
104838
  `Read-only member "${member.name}" has a non-Immutable owned default child "${owned.name}"; ${ownerLabel}.`
@@ -106561,7 +106977,10 @@ function assertProjectVersionWholeGraphWritesValid(args) {
106561
106977
  assertStagedInternalRecordRelationsValid(args.document, projected, changes);
106562
106978
  assertStagedWorldContentLayerBindingsValid(args.document, projected, changes);
106563
106979
  assertAnimationClipDocumentValid(
106564
- materializeDeclarationInitializersForAnimationValidation(projected),
106980
+ materializeDeclarationInitializersForAnimationValidation(
106981
+ projected,
106982
+ args.animationValidationMemberIds
106983
+ ),
106565
106984
  args.animationValidationMemberIds === void 0 ? void 0 : { memberIds: args.animationValidationMemberIds }
106566
106985
  );
106567
106986
  if (args.operation === void 0 || !isSystemOwnedProjectVersionOperation(args.operation)) {
@@ -106679,7 +107098,71 @@ function valueDematerializationRefusal(args) {
106679
107098
  }
106680
107099
  return null;
106681
107100
  }
106682
- function materializeDeclarationInitializersForAnimationValidation(document) {
107101
+ function animationRootsInValidationScope(args) {
107102
+ const {
107103
+ document,
107104
+ valuesById,
107105
+ animationFamilyClassIds,
107106
+ animationRoots,
107107
+ scopeMemberIds
107108
+ } = args;
107109
+ if (scopeMemberIds === void 0 || animationRoots.length === 0) {
107110
+ return animationRoots;
107111
+ }
107112
+ const segmentIds = new Set(
107113
+ [...valuesById.values()].flatMap(
107114
+ (row) => typeof row.classId === "string" && animationFamilyClassIds.get(row.classId) === "animationSegment" ? [row.id] : []
107115
+ )
107116
+ );
107117
+ const placements = findSemanticOwnerPlacementsForValues(
107118
+ document,
107119
+ /* @__PURE__ */ new Set([...animationRoots.map((row) => row.id), ...segmentIds]),
107120
+ void 0,
107121
+ true
107122
+ );
107123
+ const segmentAncestors = /* @__PURE__ */ new Set();
107124
+ for (const segmentId of segmentIds) {
107125
+ let id2 = segmentId;
107126
+ while (id2 !== null && !segmentAncestors.has(id2)) {
107127
+ segmentAncestors.add(id2);
107128
+ id2 = placements.get(id2)?.parentValueId ?? null;
107129
+ }
107130
+ }
107131
+ const insideValidatedRootById = /* @__PURE__ */ new Map();
107132
+ return animationRoots.filter((row) => {
107133
+ if (segmentAncestors.has(row.id)) return true;
107134
+ let id2 = row.id;
107135
+ const path = [];
107136
+ const seen = /* @__PURE__ */ new Set();
107137
+ let insideValidatedRoot = false;
107138
+ while (id2 !== null && !seen.has(id2)) {
107139
+ const cached = insideValidatedRootById.get(id2);
107140
+ if (cached !== void 0) {
107141
+ insideValidatedRoot = cached;
107142
+ break;
107143
+ }
107144
+ if (segmentIds.has(id2)) {
107145
+ insideValidatedRoot = true;
107146
+ break;
107147
+ }
107148
+ seen.add(id2);
107149
+ path.push(id2);
107150
+ const placement = placements.get(id2);
107151
+ if (placement === void 0) break;
107152
+ if (placement.parentValueId === null) {
107153
+ const memberId = getField(placement.member, "id");
107154
+ insideValidatedRoot = typeof memberId === "string" && scopeMemberIds.has(memberId);
107155
+ break;
107156
+ }
107157
+ id2 = placement.parentValueId;
107158
+ }
107159
+ for (const valueId of path) {
107160
+ insideValidatedRootById.set(valueId, insideValidatedRoot);
107161
+ }
107162
+ return insideValidatedRoot;
107163
+ });
107164
+ }
107165
+ function materializeDeclarationInitializersForAnimationValidation(document, scopeMemberIds) {
106683
107166
  const animationFamilyClassIds = animationFamilyClassKinds(document.classes);
106684
107167
  const initializers = document.values.filter(
106685
107168
  (value) => isInitValueContent(value)
@@ -106692,12 +107175,13 @@ function materializeDeclarationInitializersForAnimationValidation(document) {
106692
107175
  if (initializers.length === 0 && defaultInitializerMemberIds.size === 0) {
106693
107176
  return document;
106694
107177
  }
107178
+ const initializerRootOwners = /* @__PURE__ */ new Map();
106695
107179
  const rootKinds = /* @__PURE__ */ new Map();
106696
107180
  const owners = resolveSemanticOwnerMembersForValues(
106697
107181
  document,
106698
107182
  new Set(initializers.map((value) => value.id)),
106699
107183
  void 0,
106700
- void 0,
107184
+ initializerRootOwners,
106701
107185
  rootKinds
106702
107186
  );
106703
107187
  const valuesById = new Map(
@@ -106706,6 +107190,7 @@ function materializeDeclarationInitializersForAnimationValidation(document) {
106706
107190
  const materializationBatch = createInitializerMaterializationBatch(document);
106707
107191
  let members = document.members;
106708
107192
  const deferred = /* @__PURE__ */ new Set();
107193
+ const parameterizedDeclarationMemberIds = /* @__PURE__ */ new Set();
106709
107194
  if (defaultInitializerMemberIds.size > 0) {
106710
107195
  members = document.members.map((member) => {
106711
107196
  if (!defaultInitializerMemberIds.has(member.id)) return member;
@@ -106713,6 +107198,7 @@ function materializeDeclarationInitializersForAnimationValidation(document) {
106713
107198
  if (!isInitValueContent(defaultValue)) return member;
106714
107199
  const parameters = defaultValue.init.compiled?.parameters;
106715
107200
  if (parameters === void 0 || parameters.length > 2) {
107201
+ parameterizedDeclarationMemberIds.add(member.id);
106716
107202
  const deferredMember = { ...member };
106717
107203
  delete deferredMember.defaultValue;
106718
107204
  delete deferredMember.valueId;
@@ -106751,6 +107237,11 @@ function materializeDeclarationInitializersForAnimationValidation(document) {
106751
107237
  const parameters = row.init.compiled?.parameters;
106752
107238
  if (parameters === void 0 || parameters.length > 2) {
106753
107239
  deferred.add(row.id);
107240
+ const rootOwner = initializerRootOwners.get(row.id);
107241
+ const rootOwnerId = rootOwner === void 0 ? void 0 : getField(rootOwner, "id");
107242
+ if (typeof rootOwnerId === "string") {
107243
+ parameterizedDeclarationMemberIds.add(rootOwnerId);
107244
+ }
106754
107245
  continue;
106755
107246
  }
106756
107247
  const materialized = materializeInitializerValue2({
@@ -106767,6 +107258,73 @@ function materializeDeclarationInitializersForAnimationValidation(document) {
106767
107258
  valuesById.set(created.id, created);
106768
107259
  }
106769
107260
  }
107261
+ const expandedRows = /* @__PURE__ */ new Map();
107262
+ const classesById = new Map(
107263
+ document.classes.map((entry) => [entry.id, entry])
107264
+ );
107265
+ const membersById = new Map(
107266
+ document.members.map((entry) => [entry.id, entry])
107267
+ );
107268
+ const classNeedsExpansion = /* @__PURE__ */ new Map();
107269
+ const memberHasParameterizedDefault = /* @__PURE__ */ new Map();
107270
+ const reachesParameterizedDefault = (memberId) => {
107271
+ const path = [];
107272
+ const visited = /* @__PURE__ */ new Set();
107273
+ let currentId = memberId;
107274
+ let result = false;
107275
+ while (currentId !== void 0 && !visited.has(currentId)) {
107276
+ const cached = memberHasParameterizedDefault.get(currentId);
107277
+ if (cached !== void 0) {
107278
+ result = cached;
107279
+ break;
107280
+ }
107281
+ if (parameterizedDeclarationMemberIds.has(currentId)) {
107282
+ result = true;
107283
+ break;
107284
+ }
107285
+ visited.add(currentId);
107286
+ path.push(currentId);
107287
+ currentId = membersById.get(currentId)?.extendsMemberId;
107288
+ }
107289
+ for (const id2 of path) memberHasParameterizedDefault.set(id2, result);
107290
+ return result;
107291
+ };
107292
+ const inheritsParameterizedDefault = (classId) => {
107293
+ const cached = classNeedsExpansion.get(classId);
107294
+ if (cached !== void 0) return cached;
107295
+ const schemaClass2 = classesById.get(classId);
107296
+ if (schemaClass2 === void 0) return false;
107297
+ classNeedsExpansion.set(classId, false);
107298
+ for (const memberId of Object.values(schemaClass2.schema)) {
107299
+ if (reachesParameterizedDefault(memberId)) {
107300
+ classNeedsExpansion.set(classId, true);
107301
+ return true;
107302
+ }
107303
+ }
107304
+ const result = typeof schemaClass2.extendsClassId === "string" && inheritsParameterizedDefault(schemaClass2.extendsClassId);
107305
+ classNeedsExpansion.set(classId, result);
107306
+ return result;
107307
+ };
107308
+ const animationRoots = parameterizedDeclarationMemberIds.size === 0 ? [] : [...valuesById.values()].filter(
107309
+ (row) => isLiteralValueContent(row) && isVirtualInstanceRootShape(row) && typeof row.classId === "string" && animationFamilyClassIds.has(row.classId) && inheritsParameterizedDefault(row.classId)
107310
+ );
107311
+ const rootsToExpand = animationRootsInValidationScope({
107312
+ document,
107313
+ valuesById,
107314
+ animationFamilyClassIds,
107315
+ animationRoots,
107316
+ scopeMemberIds
107317
+ });
107318
+ if (rootsToExpand.length > 0) {
107319
+ const lookups = initializerEvaluatorLookups(
107320
+ materializationBatch.document()
107321
+ );
107322
+ for (const root of rootsToExpand) {
107323
+ for (const row of lookups.virtualInstanceRowsForValue(root.id)) {
107324
+ expandedRows.set(row.id, row);
107325
+ }
107326
+ }
107327
+ }
106770
107328
  if (deferred.size > 0) {
106771
107329
  for (const id2 of deferred) valuesById.delete(id2);
106772
107330
  members = members.map((member) => {
@@ -106858,6 +107416,9 @@ function materializeDeclarationInitializersForAnimationValidation(document) {
106858
107416
  }
106859
107417
  }
106860
107418
  }
107419
+ for (const [id2, row] of expandedRows) {
107420
+ if (!deferred.has(id2)) valuesById.set(id2, row);
107421
+ }
106861
107422
  return { ...document, members, values: [...valuesById.values()] };
106862
107423
  }
106863
107424
  function containsDirectValueId(value, ids) {
@@ -107596,6 +108157,7 @@ var init_project_version_whole_graph_validation = __esm({
107596
108157
  init_project_version_system_protection_writes();
107597
108158
  init_reserved_record_id_validation();
107598
108159
  init_members();
108160
+ init_instance_provenance();
107599
108161
  init_generics();
107600
108162
  init_inheritance();
107601
108163
  init_neoscript();
@@ -110927,29 +111489,25 @@ function lowerExpressionValue(context, expression, declaredExpected, ownerClass,
110927
111489
  }
110928
111490
  case "litDict": {
110929
111491
  const valueType = expected.arguments[1] ?? expected;
111492
+ const keyType = expected.arguments[0];
111493
+ const keyEnumId = context.enumIdsByName.get(keyType?.name ?? "");
111494
+ const keyEnum = keyEnumId === void 0 ? null : {
111495
+ name: keyType.name,
111496
+ optionsByName: context.enumOptionsByName.get(keyEnumId) ?? /* @__PURE__ */ new Map()
111497
+ };
110930
111498
  const value = {};
110931
111499
  for (const entry of expression.entries) {
110932
111500
  if (positionRequiresEvaluation(
110933
111501
  context,
110934
111502
  entry.key,
110935
- DICTIONARY_KEY_TYPE,
111503
+ keyType ?? expected,
110936
111504
  ownerClass
110937
111505
  )) {
110938
111506
  throw new Error(
110939
- `Dictionary key at ${path} is a computed expression. Dictionary keys must be string literals.`
111507
+ `Dictionary key at ${path} is a computed expression. Dictionary keys must be ${keyEnum === null ? "string literals" : "enum options or quoted option IDs"}.`
110940
111508
  );
110941
111509
  }
110942
- const key = lowerExpressionValue(
110943
- context,
110944
- entry.key,
110945
- DICTIONARY_KEY_TYPE,
110946
- ownerClass,
110947
- path,
110948
- genericEnvironment,
110949
- sourceText
110950
- );
110951
- if (typeof key !== "string")
110952
- throw new Error("Dictionary keys must be strings.");
111510
+ const key = lowerDictionaryKey(entry.key, keyEnum, path);
110953
111511
  value[key] = lowerExpressionValue(
110954
111512
  context,
110955
111513
  entry.value,
@@ -112072,7 +112630,7 @@ function variantPathSegments2(expression) {
112072
112630
  if (segments.length < 3) return null;
112073
112631
  return segments;
112074
112632
  }
112075
- var UNSET_LIST_COLUMN_WIDTH, EMPTY_GENERIC_TYPE_ENVIRONMENT, DICTIONARY_KEY_TYPE, STRUCTURED_LEAF_COMPONENT_TYPE, primitiveMemberKinds;
112633
+ var UNSET_LIST_COLUMN_WIDTH, EMPTY_GENERIC_TYPE_ENVIRONMENT, STRUCTURED_LEAF_COMPONENT_TYPE, primitiveMemberKinds;
112076
112634
  var init_lower_members = __esm({
112077
112635
  "src/project-source/lower-members.ts"() {
112078
112636
  "use strict";
@@ -112091,13 +112649,9 @@ var init_lower_members = __esm({
112091
112649
  init_member_kind_type_names();
112092
112650
  init_source_diagnostics();
112093
112651
  init_key_reference_spelling();
112652
+ init_dictionary_enum_keys();
112094
112653
  UNSET_LIST_COLUMN_WIDTH = -1;
112095
112654
  EMPTY_GENERIC_TYPE_ENVIRONMENT = /* @__PURE__ */ new Map();
112096
- DICTIONARY_KEY_TYPE = {
112097
- name: "string",
112098
- nullable: false,
112099
- arguments: []
112100
- };
112101
112655
  STRUCTURED_LEAF_COMPONENT_TYPE = {
112102
112656
  name: "float",
112103
112657
  nullable: false,
@@ -116355,6 +116909,23 @@ var init_neoscript_build_cache = __esm({
116355
116909
  });
116356
116910
 
116357
116911
  // src/project-source/local-initializer-materialization.ts
116912
+ function initializerRecompileTargets(args) {
116913
+ return collectNeoScriptRecompileTargets({
116914
+ currentDocument: args.currentDocument,
116915
+ postDocument: args.postDocument,
116916
+ forceRecompile: args.forceRecompile,
116917
+ changes: args.changes.map((change) => {
116918
+ const operation = "operation" in change ? change.operation : change.kind;
116919
+ return {
116920
+ recordKind: change.recordKind,
116921
+ recordId: change.recordId,
116922
+ operation,
116923
+ ...operation === "delete" ? { deleted: true } : {},
116924
+ ...change.nextData === void 0 ? {} : { nextData: change.nextData }
116925
+ };
116926
+ })
116927
+ });
116928
+ }
116358
116929
  function materializedInitializerReconciliationFailuresV4(args) {
116359
116930
  if (args.reconciliations.size === 0) return [];
116360
116931
  const records2 = reconciliationRecords(
@@ -116365,17 +116936,11 @@ function materializedInitializerReconciliationFailuresV4(args) {
116365
116936
  const document = readPulledProjectDocumentV4(records2);
116366
116937
  const currentRecords = reconciliationRecords(args.workspace, []);
116367
116938
  const currentDocument = readPulledProjectDocumentV4(currentRecords);
116368
- const recompileTargets = collectNeoScriptRecompileTargets({
116939
+ const recompileTargets = initializerRecompileTargets({
116369
116940
  currentDocument,
116370
116941
  postDocument: document,
116371
116942
  forceRecompile: args.forceRecompile,
116372
- changes: args.changes.map((change) => ({
116373
- recordKind: change.recordKind,
116374
- recordId: change.recordId,
116375
- operation: change.kind,
116376
- ...change.kind === "delete" ? { deleted: true } : {},
116377
- ...change.nextData === void 0 ? {} : { nextData: change.nextData }
116378
- }))
116943
+ changes: args.changes
116379
116944
  });
116380
116945
  const reconciliationByValueId = /* @__PURE__ */ new Map();
116381
116946
  const candidateValueIds = /* @__PURE__ */ new Set();
@@ -116448,8 +117013,14 @@ function materializedInitializerReconciliationFailuresV4(args) {
116448
117013
  let compilationProject;
116449
117014
  if (replayableValueIds.size > 0) {
116450
117015
  compilationProject = args.useBuildCaches === false ? createNeoScriptCompilationProject(document) : loadOrBuildNeoScriptProjectV1(args.workspace.root, document);
117016
+ compilePulledProjectDocumentForEvaluationV4(
117017
+ document,
117018
+ compilationProject,
117019
+ recompileTargets
117020
+ );
116451
117021
  }
116452
- const replayContext = replayableValueIds.size > 0 ? createPulledConstructionReplayContext({ document }) : void 0;
117022
+ const replayDocument = replayableValueIds.size > 0 ? { ...document } : document;
117023
+ const replayContext = replayableValueIds.size > 0 ? createPulledConstructionReplayContext({ document: replayDocument }) : void 0;
116453
117024
  let currentRows;
116454
117025
  let currentReader;
116455
117026
  const failures = [];
@@ -116484,7 +117055,7 @@ function materializedInitializerReconciliationFailuresV4(args) {
116484
117055
  const replayRows = /* @__PURE__ */ new Map();
116485
117056
  for (const [id2, row] of replayStoredConstructionV4({
116486
117057
  records: records2,
116487
- document,
117058
+ document: replayDocument,
116488
117059
  replayContext,
116489
117060
  valueId: reconciliation.valueId,
116490
117061
  code: reconciliation.code,
@@ -116498,9 +117069,9 @@ function materializedInitializerReconciliationFailuresV4(args) {
116498
117069
  }
116499
117070
  replayRows.set(id2, row);
116500
117071
  }
116501
- assertPulledConstructorsCompiled(document, replayContext);
117072
+ assertPulledConstructorsCompiled(replayDocument, replayContext);
116502
117073
  currentRows ??= new Map(currentDocument.values.map((row) => [row.id, row]));
116503
- currentReader ??= new EffectiveValueReader(document, currentRows);
117074
+ currentReader ??= new EffectiveValueReader(replayDocument, currentRows);
116504
117075
  const replay = replayRows.get(reconciliation.valueId);
116505
117076
  const replayArgs = replay !== void 0 && isLiteralValueContent(replay) ? replay.constructorArgs : void 0;
116506
117077
  const currentRoot = currentRows.get(reconciliation.valueId);
@@ -116558,10 +117129,10 @@ function materializeInitializersLocallyV4(args) {
116558
117129
  readPulledProjectDocumentV4(records2),
116559
117130
  variantOwnershipRootRecords(records2)
116560
117131
  );
116561
- let document = variantScope.document;
117132
+ const authoredDocument = variantScope.document;
116562
117133
  const rootKinds = /* @__PURE__ */ new Map();
116563
117134
  const rootOwners = resolveSemanticOwnerMembersForValues(
116564
- document,
117135
+ authoredDocument,
116565
117136
  sourceRoots,
116566
117137
  variantScope.roots,
116567
117138
  void 0,
@@ -116569,19 +117140,73 @@ function materializeInitializersLocallyV4(args) {
116569
117140
  );
116570
117141
  const roots = [];
116571
117142
  const localizedTextIds = new Set(
116572
- document.localizedTexts?.map((text) => text.id)
117143
+ authoredDocument.localizedTexts?.map((text) => text.id)
116573
117144
  );
116574
- let compilationProject;
116575
- for (const sourceValueId of [...sourceRoots].sort()) {
116576
- if (rootKinds.get(sourceValueId) === "declaration") continue;
117145
+ const pendingRoots = new Set(
117146
+ [...sourceRoots].filter((id2) => rootKinds.get(id2) !== "declaration").sort()
117147
+ );
117148
+ if (pendingRoots.size === 0) return { roots };
117149
+ const compilationProject = createNeoScriptCompilationProject(authoredDocument);
117150
+ const changedBodies = {
117151
+ memberIds: /* @__PURE__ */ new Set(),
117152
+ constructorIds: /* @__PURE__ */ new Set()
117153
+ };
117154
+ for (const change of args.changes) {
117155
+ if (change.operation === "delete") continue;
117156
+ if (change.recordKind === "member") {
117157
+ changedBodies.memberIds.add(change.recordId);
117158
+ } else if (change.recordKind === "constructor") {
117159
+ changedBodies.constructorIds.add(change.recordId);
117160
+ }
117161
+ }
117162
+ const needsDependentBodies = args.forceRecompile === true || args.changes.some(
117163
+ (change) => ["class", "member", "constructor", "enum", "interface"].includes(
117164
+ change.recordKind
117165
+ )
117166
+ );
117167
+ if (needsDependentBodies) {
117168
+ const currentDocument = readPulledProjectDocumentV4(
117169
+ reconciliationRecords(args.workspace, [])
117170
+ );
117171
+ const dependentBodies = initializerRecompileTargets({
117172
+ currentDocument,
117173
+ postDocument: authoredDocument,
117174
+ changes: args.changes,
117175
+ forceRecompile: args.forceRecompile
117176
+ });
117177
+ for (const id2 of dependentBodies.memberIds) changedBodies.memberIds.add(id2);
117178
+ for (const id2 of dependentBodies.constructorIds) {
117179
+ changedBodies.constructorIds.add(id2);
117180
+ }
117181
+ }
117182
+ compilePulledProjectDocumentForEvaluationV4(
117183
+ authoredDocument,
117184
+ compilationProject,
117185
+ changedBodies
117186
+ );
117187
+ assertPulledConstructorsCompiled(authoredDocument);
117188
+ const batch = createInitializerMaterializationBatch(
117189
+ authoredDocument,
117190
+ pendingRoots
117191
+ );
117192
+ const compiledInitializers = /* @__PURE__ */ new Map();
117193
+ materializeInitializerDependencies(pendingRoots, (sourceValueId) => {
117194
+ const batchDocument = batch.document();
117195
+ const document = {
117196
+ ...authoredDocument,
117197
+ values: batchDocument.values,
117198
+ databaseVM: batchDocument.databaseVM
117199
+ };
116577
117200
  const rootOwner = rootOwners.get(sourceValueId);
116578
117201
  if (rootOwner === void 0) {
116579
117202
  throw new Error(
116580
117203
  `CLI initializer materialization cannot resolve the owning member for root "${sourceValueId}".`
116581
117204
  );
116582
117205
  }
116583
- compilationProject ??= createNeoScriptCompilationProject(document);
116584
- const replayContext = createPulledConstructionReplayContext({ document });
117206
+ const replayContext = createPulledConstructionReplayContext({
117207
+ document,
117208
+ valuesById: batch.valuesById
117209
+ });
116585
117210
  const code = initializerCode(records2, sourceValueId);
116586
117211
  let compiledInitializer;
116587
117212
  let pinnedRootSchemaKeys = /* @__PURE__ */ new Set();
@@ -116593,8 +117218,10 @@ function materializeInitializersLocallyV4(args) {
116593
117218
  compilationProject,
116594
117219
  replayContext,
116595
117220
  member: rootOwner,
117221
+ compiledInitializer: compiledInitializers.get(sourceValueId),
116596
117222
  onCompiledInitializer: (init) => {
116597
117223
  compiledInitializer = init;
117224
+ compiledInitializers.set(sourceValueId, init);
116598
117225
  },
116599
117226
  onPinnedRootSchemaKeys: (schemaKeys) => {
116600
117227
  pinnedRootSchemaKeys = schemaKeys;
@@ -116628,6 +117255,7 @@ function materializeInitializersLocallyV4(args) {
116628
117255
  compilationProject,
116629
117256
  replayContext,
116630
117257
  member: rootOwner,
117258
+ compiledInitializer,
116631
117259
  omitConstructionFields: true
116632
117260
  });
116633
117261
  const baselineRoot = baseline.get(sourceValueId);
@@ -116661,15 +117289,9 @@ function materializeInitializersLocallyV4(args) {
116661
117289
  // class default, so the evaluated construction's own field list is what
116662
117290
  // pins rows against collapse. The server commit pins the same set.
116663
117291
  pinnedRootSchemaKeys,
116664
- virtualValueIdForSource: (instanceRootId, sourceIdentity3) => isPendingId(instanceRootId) ? pendingVirtualValueId(instanceRootId, sourceIdentity3) : virtualValueId(instanceRootId, sourceIdentity3)
117292
+ virtualValueIdForSource: (instanceRootId, sourceIdentity3) => isPendingId(instanceRootId) || hasPendingVirtualSourceIdentity(sourceIdentity3) ? pendingVirtualValueId(instanceRootId, sourceIdentity3) : virtualValueId(instanceRootId, sourceIdentity3)
116665
117293
  });
116666
117294
  const evaluatedRows = [sparse2.root, ...sparse2.createdChildren];
116667
- const valuesById = new Map(document.values.map((row) => [row.id, row]));
116668
- for (const row of evaluatedRows) valuesById.set(row.id, row);
116669
- const materializedDocument = {
116670
- ...document,
116671
- values: [...valuesById.values()]
116672
- };
116673
117295
  roots.push({
116674
117296
  sourceValueId,
116675
117297
  rows: evaluatedRows.map((row) => ({ ...row }))
@@ -116683,8 +117305,8 @@ function materializeInitializersLocallyV4(args) {
116683
117305
  data: row
116684
117306
  });
116685
117307
  }
116686
- document = materializedDocument;
116687
- }
117308
+ batch.upsert(evaluatedRows);
117309
+ });
116688
117310
  return { roots };
116689
117311
  }
116690
117312
  function prospectiveInitializerRecordsV4(args) {
@@ -116833,6 +117455,8 @@ function variantOwnershipRootRecords(records2) {
116833
117455
  var init_local_initializer_materialization = __esm({
116834
117456
  "src/project-source/local-initializer-materialization.ts"() {
116835
117457
  "use strict";
117458
+ init_evaluateInitializer();
117459
+ init_initializer_dependencies();
116836
117460
  init_initializer_replay();
116837
117461
  init_effective_value_comparison();
116838
117462
  init_constructor_argument_ownership();
@@ -117750,6 +118374,7 @@ function computeWorkspaceStatus(workspace, options) {
117750
118374
  try {
117751
118375
  localInitializerMaterialization = materializeInitializersLocallyV4({
117752
118376
  workspace,
118377
+ forceRecompile: options.forceRecompile,
117753
118378
  changes: changes.map((change) => ({
117754
118379
  recordKind: change.recordKind,
117755
118380
  recordId: change.recordId,
@@ -117882,9 +118507,11 @@ function replayAnimationDeclarationInitializersV4(records2, document, fallbackDo
117882
118507
  ...document.values.map((row) => [row.id, row])
117883
118508
  ]);
117884
118509
  for (const { row, code } of initializers) {
117885
- if (rootKinds.get(row.id) !== "declaration") continue;
117886
118510
  const owner = owners.get(row.id);
117887
118511
  if (owner === void 0) continue;
118512
+ if (rootKinds.get(row.id) !== "declaration" && !isStaticMember(owner)) {
118513
+ continue;
118514
+ }
117888
118515
  const declaredClassId = typeof row.classId === "string" ? row.classId : Reflect.get(owner, "classId");
117889
118516
  if (typeof declaredClassId !== "string") continue;
117890
118517
  if (!classBelongsToAnimationFamily(document.classesById, declaredClassId)) {
@@ -118856,6 +119483,7 @@ function verifyProjectSourceCommitAgainstStateV4(args) {
118856
119483
  }
118857
119484
  }
118858
119485
  const status = computeWorkspaceStatus(workspace, {
119486
+ forceRecompile: args.forceRecompile,
118859
119487
  skipProjectBinaryInspection: true,
118860
119488
  useBuildCaches: false,
118861
119489
  writeProjectAnalysisCache: () => void 0,
@@ -119021,7 +119649,18 @@ function derivedAssignment(pendingId2) {
119021
119649
  if (virtualIdentity !== null) {
119022
119650
  return {
119023
119651
  ownerLocator: virtualIdentity.instanceRootId,
119024
- derive: (ownerId) => virtualValueId(ownerId, virtualIdentity.sourceIdentity),
119652
+ derive: (ownerId, assignments) => virtualValueId(
119653
+ ownerId,
119654
+ rewriteVirtualSourceIdentity(virtualIdentity.sourceIdentity, (id2) => {
119655
+ const assigned = assignments.get(id2);
119656
+ if (assigned === void 0) {
119657
+ throw new ProjectSourceCommitVerificationError(
119658
+ `Virtual value assignment ${pendingId2} names source ${id2}, which has no pending id assignment.`
119659
+ );
119660
+ }
119661
+ return assigned;
119662
+ })
119663
+ ),
119025
119664
  label: "Virtual value assignment",
119026
119665
  ownerNoun: "instance root"
119027
119666
  };
@@ -119038,7 +119677,7 @@ function assertDerivedAssignmentsAreDerived(assignments) {
119038
119677
  `${derivation.label} ${pendingId2} names ${derivation.ownerNoun} ${derivation.ownerLocator}, which has no pending id assignment.`
119039
119678
  );
119040
119679
  }
119041
- const derived = derivation.derive(ownerId);
119680
+ const derived = derivation.derive(ownerId, assignments);
119042
119681
  if (assignedId !== derived) {
119043
119682
  throw new ProjectSourceCommitVerificationError(
119044
119683
  `${derivation.label} ${pendingId2} is ${assignedId}, but ${derivation.ownerNoun} ${ownerId} owns ${derived}.`
@@ -119068,24 +119707,51 @@ function positionIndependentAssignments(assignments) {
119068
119707
  }
119069
119708
  return resolved;
119070
119709
  }
119071
- function relocatedAssignment(pendingId2, assignments, byPosition) {
119710
+ function relocatedAssignment(pendingId2, assignments, byPosition, used) {
119072
119711
  const key = positionIndependentPendingKey(pendingId2);
119073
119712
  const relocated = key === null ? void 0 : byPosition.get(key);
119074
119713
  if (relocated !== void 0) return relocated;
119714
+ for (const [owner, rebuild] of [
119715
+ [pendingMemberValueMemberId(pendingId2), pendingMemberValueId],
119716
+ [pendingEntryMemberDeclaringId(pendingId2), pendingEntryMemberId],
119717
+ [
119718
+ pendingRequiredConstructorClassId(pendingId2),
119719
+ pendingRequiredConstructorId
119720
+ ]
119721
+ ]) {
119722
+ if (owner === null) continue;
119723
+ const relocatedOwner = assignments.has(owner) ? owner : relocatedAssignment(owner, assignments, byPosition, used);
119724
+ if (relocatedOwner === null) return null;
119725
+ const rebuilt = rebuild(relocatedOwner);
119726
+ return assignments.has(rebuilt) ? rebuilt : null;
119727
+ }
119075
119728
  const virtual = pendingVirtualValueIdentity(pendingId2);
119076
119729
  if (virtual === null) return null;
119077
119730
  let relocatedRoot = virtual.instanceRootId;
119078
- if (!assignments.has(relocatedRoot)) {
119079
- const rootKey = positionIndependentPendingKey(relocatedRoot);
119080
- if (rootKey === null) return null;
119081
- const canonicalRoot = byPosition.get(rootKey);
119082
- if (canonicalRoot === void 0) return null;
119731
+ if (isPendingId(relocatedRoot) && !assignments.has(relocatedRoot)) {
119732
+ const canonicalRoot = relocatedAssignment(
119733
+ relocatedRoot,
119734
+ assignments,
119735
+ byPosition,
119736
+ used
119737
+ );
119738
+ if (canonicalRoot === null) return null;
119083
119739
  relocatedRoot = canonicalRoot;
119084
119740
  }
119085
- const relocatedVirtual = pendingVirtualValueId(
119086
- relocatedRoot,
119087
- virtual.sourceIdentity
119741
+ const sourceIdentity3 = rewriteVirtualSourceIdentity(
119742
+ virtual.sourceIdentity,
119743
+ (sourceId3) => {
119744
+ const relocatedSource = assignments.has(sourceId3) ? sourceId3 : relocatedAssignment(sourceId3, assignments, byPosition, used);
119745
+ if (relocatedSource === null) {
119746
+ throw new ProjectSourceCommitVerificationError(
119747
+ `Virtual value ${pendingId2} names source ${sourceId3}, which has no pending id assignment.`
119748
+ );
119749
+ }
119750
+ used.add(relocatedSource);
119751
+ return relocatedSource;
119752
+ }
119088
119753
  );
119754
+ const relocatedVirtual = pendingVirtualValueId(relocatedRoot, sourceIdentity3);
119089
119755
  return assignments.has(relocatedVirtual) ? relocatedVirtual : null;
119090
119756
  }
119091
119757
  function rewritePending(value, assignments, used, positionless) {
@@ -119096,7 +119762,12 @@ function rewritePending(value, assignments, used, positionless) {
119096
119762
  return exact;
119097
119763
  }
119098
119764
  if (value.startsWith("__pending__:")) {
119099
- const relocated = relocatedAssignment(value, assignments, positionless);
119765
+ const relocated = relocatedAssignment(
119766
+ value,
119767
+ assignments,
119768
+ positionless,
119769
+ used
119770
+ );
119100
119771
  if (relocated !== null) {
119101
119772
  used.add(relocated);
119102
119773
  return assignments.get(relocated);
@@ -119958,7 +120629,7 @@ function createPulledConstructionReplayContext(args) {
119958
120629
  return {
119959
120630
  document: args.document,
119960
120631
  constructorsValidated: false,
119961
- valuesById: new Map(args.document.values.map((value) => [value.id, value]))
120632
+ valuesById: args.valuesById ?? new Map(args.document.values.map((value) => [value.id, value]))
119962
120633
  };
119963
120634
  }
119964
120635
  function describePulledProjectBodyCompileError(error) {
@@ -120034,26 +120705,27 @@ function replayStoredConstructionV4(args) {
120034
120705
  delete envelope.init;
120035
120706
  const candidate = {
120036
120707
  ...envelope,
120037
- init: { code: args.code }
120708
+ init: args.compiledInitializer ?? { code: args.code }
120038
120709
  };
120039
- compileValueRowInitializerBody({
120040
- project: document.project,
120041
- projectFiles: document.projectFiles,
120042
- members: document.members,
120043
- classes: document.classes,
120044
- enums: document.enums,
120045
- interfaces: document.interfaces,
120046
- constructors: document.constructors,
120047
- member: compileMember,
120048
- valueRow: candidate,
120049
- valueId: args.valueId,
120050
- // Instance calls are self-contained. Declaration calls inherit the class
120051
- // header parameters that are in lexical scope at their source site.
120052
- initializerOwnerClass: args.initializerOwnerClass ?? null,
120053
- lexicalThisClass: args.lexicalThisClass ?? null,
120054
- storedConstructionReplay: true,
120055
- ...compilationProject === void 0 ? {} : { compilationProject }
120056
- });
120710
+ if (args.compiledInitializer === void 0)
120711
+ compileValueRowInitializerBody({
120712
+ project: document.project,
120713
+ projectFiles: document.projectFiles,
120714
+ members: document.members,
120715
+ classes: document.classes,
120716
+ enums: document.enums,
120717
+ interfaces: document.interfaces,
120718
+ constructors: document.constructors,
120719
+ member: compileMember,
120720
+ valueRow: candidate,
120721
+ valueId: args.valueId,
120722
+ // Instance calls are self-contained. Declaration calls inherit the class
120723
+ // header parameters that are in lexical scope at their source site.
120724
+ initializerOwnerClass: args.initializerOwnerClass ?? null,
120725
+ lexicalThisClass: args.lexicalThisClass ?? null,
120726
+ storedConstructionReplay: true,
120727
+ ...compilationProject === void 0 ? {} : { compilationProject }
120728
+ });
120057
120729
  if (!isMemberValue(candidate) || !isInitValueContent(candidate)) {
120058
120730
  throw new Error(
120059
120731
  `Construction replay for value "${args.valueId}" did not compile an initializer row.`
@@ -120131,7 +120803,7 @@ function compilePulledUncompiledConstructorsV4(document, compilationProject, rep
120131
120803
  }
120132
120804
  assertPulledConstructorsCompiled(document, replayContext);
120133
120805
  }
120134
- function compilePulledProjectDocumentForEvaluationV4(document, compilationProject) {
120806
+ function compilePulledProjectDocumentForEvaluationV4(document, compilationProject, targets) {
120135
120807
  const sharedCompilationProject = compilationProject ?? createNeoScriptCompilationProject({
120136
120808
  project: document.project,
120137
120809
  projectFiles: document.projectFiles,
@@ -120153,11 +120825,15 @@ function compilePulledProjectDocumentForEvaluationV4(document, compilationProjec
120153
120825
  compilationProject: sharedCompilationProject
120154
120826
  };
120155
120827
  for (const constructor2 of compileArgs.constructors) {
120828
+ if (targets !== void 0 && !targets.constructorIds.has(constructor2.id) && !hasPendingNeoScriptDerivation("constructor", constructor2))
120829
+ continue;
120156
120830
  compileConstructorRecord({ ...compileArgs, constructor: constructor2 });
120157
120831
  }
120158
120832
  assertPulledConstructorsCompiled(document);
120159
120833
  const memberIndex = documentMemberCompilationIndex(document);
120160
120834
  for (const member of compileArgs.members) {
120835
+ if (targets !== void 0 && !targets.memberIds.has(member.id) && !hasPendingNeoScriptDerivation("member", member))
120836
+ continue;
120161
120837
  try {
120162
120838
  compileAuthoredMemberBodies({
120163
120839
  ...compileArgs,
@@ -120344,6 +121020,7 @@ var init_initializer_replay = __esm({
120344
121020
  init_server_preparation_preflight();
120345
121021
  init_projection();
120346
121022
  init_constructors2();
121023
+ init_neo_script_derived_bodies();
120347
121024
  init_compiler_adapter();
120348
121025
  pulledBodyCompileSites = /* @__PURE__ */ new WeakMap();
120349
121026
  recentPulledDocuments = [];
@@ -120437,6 +121114,7 @@ function buildValueEmitContext(records2, manifest, options = {}) {
120437
121114
  ownerClassIds: memberOwnerClassIdIndex(classes),
120438
121115
  values,
120439
121116
  enums,
121117
+ dictionaryKeyOptions: /* @__PURE__ */ new Map(),
120440
121118
  localizedTexts,
120441
121119
  mainLocale: projectMainLocale(records2),
120442
121120
  symbolsByValueId,
@@ -121000,6 +121678,7 @@ function buildValueLowerContext(state, manifest, options = {}) {
121000
121678
  new Map(entry.options.map((option) => [option.name, option.id]))
121001
121679
  ])
121002
121680
  ),
121681
+ enumNames: new Map(manifest.enums.map((entry) => [entry.id, entry.name])),
121003
121682
  staticValueIdsBySymbol: staticTargets,
121004
121683
  get rootValueTargetsByPath() {
121005
121684
  return rootValueTargets ??= rootValueTargetsByPath(
@@ -121630,15 +122309,17 @@ function lowerMemberDefaultSourcesV4(state, analysis, manifest, options = {}) {
121630
122309
  `Member default ${label} was classified as an owned literal graph but lowered as an initializer.`
121631
122310
  );
121632
122311
  }
121633
- if (storedDefault !== null && canonicallyEqual(seed.value, storedDefault.value) && (seed.classId ?? null) === (typeof storedDefaultClassId === "string" ? storedDefaultClassId : null) && (seed.values === void 0 || seed.values.length === 0) && (seed.bindingMembers === void 0 || seed.bindingMembers.length === 0) && (seed.localizedTexts === void 0 || seed.localizedTexts.length === 0)) {
122312
+ const emptyInlineClassDefault = member.kind === "class" && isObjectRecord2(seed.value) && Object.keys(seed.value).length === 0 && (seed.constructorArgs === void 0 || Object.keys(seed.constructorArgs).length === 0) && seed.instanceConstructorId == null && seed.instanceVariantId == null && seed.instanceVariantRowValueId == null;
122313
+ const matchesStoredDefault = storedDefault !== null && canonicallyEqual(seed.value, storedDefault.value) && (seed.classId ?? null) === (typeof storedDefaultClassId === "string" ? storedDefaultClassId : null);
122314
+ if ((emptyInlineClassDefault || matchesStoredDefault) && (seed.values === void 0 || seed.values.length === 0) && (seed.bindingMembers === void 0 || seed.bindingMembers.length === 0) && (seed.localizedTexts === void 0 || seed.localizedTexts.length === 0)) {
121634
122315
  for (const id2 of context.pendingValues.keys()) {
121635
122316
  if (!pendingValueIdsBeforeSeed.has(id2)) {
121636
122317
  deletePendingValue(context, id2);
121637
122318
  }
121638
122319
  }
121639
122320
  memberDefaultValues.set(memberId, {
121640
- value: storedDefault.value,
121641
- classId: typeof storedDefaultClassId === "string" ? storedDefaultClassId : null
122321
+ value: seed.value,
122322
+ classId: seed.classId
121642
122323
  });
121643
122324
  continue;
121644
122325
  }
@@ -122335,24 +123016,21 @@ function lowerRowBackedDefault(context, member, backed, baseData3, binding) {
122335
123016
  throw new Error(`Default value ${binding.label} requires {...}.`);
122336
123017
  }
122337
123018
  const entryMember = requiredMember(context, member.entryMemberId);
123019
+ const keyEnum = dictionaryKeyEnum(context, member);
122338
123020
  const baseBody = backed.body;
122339
123021
  const body = {};
122340
123022
  const entrySlices = topLevelEntrySlices(binding.initializer, "{", "}");
122341
123023
  let entryIndex = 0;
122342
123024
  for (const entry of expression.entries) {
122343
- if (entry.key.kind !== "litString") {
122344
- throw new Error(
122345
- `Default dictionary ${binding.label} requires string keys.`
122346
- );
122347
- }
122348
- const existingId = isObjectRecord2(baseBody) ? baseBody[entry.key.value] : void 0;
123025
+ const key = lowerDictionaryKey(entry.key, keyEnum, binding.label);
123026
+ const existingId = isObjectRecord2(baseBody) ? baseBody[key] : void 0;
122349
123027
  const entryId = typeof existingId === "string" ? existingId : annotatedValue(entry.value).id;
122350
123028
  if (entryId === null || entryId === void 0) {
122351
123029
  throw new Error(
122352
- `Default dictionary ${binding.label}[${JSON.stringify(entry.key.value)}] has no existing owned value row. Creating new default rows from source is not implemented by this slice.`
123030
+ `Default dictionary ${binding.label}[${JSON.stringify(key)}] has no existing owned value row. Creating new default rows from source is not implemented by this slice.`
122353
123031
  );
122354
123032
  }
122355
- body[entry.key.value] = lowerValueRow(
123033
+ body[key] = lowerValueRow(
122356
123034
  context,
122357
123035
  entryMember,
122358
123036
  entry.value,
@@ -122956,19 +123634,18 @@ function lowerSeedRow(context, member, sourceExpression, source, valueId, path,
122956
123634
  throw new Error(`Dictionary value ${path} requires {...}.`);
122957
123635
  }
122958
123636
  const entryMember = requiredMember(context, resolvedMember.entryMemberId);
123637
+ const keyEnum = dictionaryKeyEnum(context, resolvedMember);
122959
123638
  const body = {};
122960
123639
  const entrySlices = authoredSlice === void 0 ? [] : topLevelEntrySlices(authoredSlice, "{", "}");
122961
123640
  let entryIndex = 0;
122962
123641
  for (const entry of expression.entries) {
122963
- if (entry.key.kind !== "litString") {
122964
- throw new Error(`Dictionary value ${path} requires string keys.`);
122965
- }
122966
- body[entry.key.value] = lowerSeedChild(
123642
+ const key = lowerDictionaryKey(entry.key, keyEnum, path);
123643
+ body[key] = lowerSeedChild(
122967
123644
  context,
122968
123645
  entryMember,
122969
123646
  entry.value,
122970
123647
  source,
122971
- `${path}[${JSON.stringify(entry.key.value)}]`,
123648
+ `${path}[${JSON.stringify(key)}]`,
122972
123649
  rows,
122973
123650
  localizedTexts,
122974
123651
  void 0,
@@ -124587,32 +125264,31 @@ function lowerDictionaryValue(context, member, expression, base, source, inherit
124587
125264
  throw new Error("Dictionary values require {...}.");
124588
125265
  }
124589
125266
  const baseBody = isObjectRecord2(base.value) ? base.value : {};
125267
+ const keyEnum = dictionaryKeyEnum(context, member);
124590
125268
  const entryMember = requiredMember(context, member.entryMemberId);
124591
125269
  const environment = valueGenericEnvironment(base, inheritedEnvironment);
124592
125270
  const body = {};
124593
125271
  for (const entry of expression.entries) {
124594
- if (entry.key.kind !== "litString") {
124595
- throw new Error("Dictionary source keys must be strings.");
124596
- }
124597
- const existingId = baseBody[entry.key.value];
125272
+ const key = lowerDictionaryKey(entry.key, keyEnum, member.name);
125273
+ const existingId = baseBody[key];
124598
125274
  const symbolId = sourceValueSymbol(context, entry.value);
124599
125275
  if (symbolId !== null) {
124600
125276
  if (symbolId !== existingId) {
124601
125277
  throw new Error(
124602
- `Dictionary ${member.name}[${JSON.stringify(entry.key.value)}] changes value placement from ${String(existingId)} to ${symbolId}. The atomic placement transaction is not implemented by this slice.`
125278
+ `Dictionary ${member.name}[${JSON.stringify(key)}] changes value placement from ${String(existingId)} to ${symbolId}. The atomic placement transaction is not implemented by this slice.`
124603
125279
  );
124604
125280
  }
124605
- body[entry.key.value] = symbolId;
125281
+ body[key] = symbolId;
124606
125282
  continue;
124607
125283
  }
124608
125284
  const explicitId = annotatedValue(entry.value).id;
124609
125285
  const valueId = explicitId ?? existingId;
124610
125286
  if (typeof valueId !== "string") {
124611
125287
  throw new Error(
124612
- `Dictionary ${member.name}[${JSON.stringify(entry.key.value)}] has no existing row. New dictionary entries are not implemented by this slice.`
125288
+ `Dictionary ${member.name}[${JSON.stringify(key)}] has no existing row. New dictionary entries are not implemented by this slice.`
124613
125289
  );
124614
125290
  }
124615
- body[entry.key.value] = lowerValueRow(
125291
+ body[key] = lowerValueRow(
124616
125292
  context,
124617
125293
  entryMember,
124618
125294
  entry.value,
@@ -125841,6 +126517,20 @@ function requiredMember(context, id2) {
125841
126517
  if (member === void 0) throw new Error(`Missing member ${id2}.`);
125842
126518
  return member;
125843
126519
  }
126520
+ function dictionaryKeyEnum(context, member) {
126521
+ if (member.key.kind === "string") return null;
126522
+ const name = context.enumNames.get(member.key.enumId);
126523
+ const optionsByName = context.enumOptions.get(member.key.enumId);
126524
+ if (name === void 0) {
126525
+ throw new Error(`Unknown dictionary key enum ${member.key.enumId}.`);
126526
+ }
126527
+ if (optionsByName === void 0) {
126528
+ throw new Error(
126529
+ `Dictionary key enum ${member.key.enumId} has no option index.`
126530
+ );
126531
+ }
126532
+ return { name, optionsByName };
126533
+ }
125844
126534
  function requiredClassByName(context, name) {
125845
126535
  const schemaClass2 = context.classesByName.get(name);
125846
126536
  if (schemaClass2 === void 0) throw new Error(`Unknown class ${name}.`);
@@ -126983,14 +127673,13 @@ ${ids.map(
126983
127673
  if (!isObjectRecord2(row.value)) {
126984
127674
  return storedRowIdentitySource(valueId, writeIdentity, "{}");
126985
127675
  }
126986
- const entries = Object.entries(row.value).sort(
126987
- ([left], [right]) => compareCodePoints(left, right)
126988
- );
127676
+ const keyOptions = dictionaryOptions2(context, type.keyEnumId);
127677
+ const entries = orderedDictionaryEntries(row.value, keyOptions);
126989
127678
  const expression = entries.length === 0 ? "{}" : `{
126990
127679
  ${entries.flatMap(
126991
127680
  ([key, id2]) => typeof id2 === "string" ? [
126992
127681
  indentNeoSourceNonEmptyLines(
126993
- `${quote5(key)}: ${storedTypedRowSource(
127682
+ `${emitDictionaryKey(key, keyOptions)}: ${storedTypedRowSource(
126994
127683
  context,
126995
127684
  type.entryType,
126996
127685
  id2,
@@ -127414,22 +128103,29 @@ function dictionaryValue(context, member, value, visited, inheritedEnvironment)
127414
128103
  if (entryMember === void 0)
127415
128104
  throw new Error(`Dictionary entry member was not pulled.`);
127416
128105
  const environment = valueGenericEnvironment(value, inheritedEnvironment);
127417
- const entries = Object.entries(body).sort(
127418
- ([left], [right]) => compareCodePoints(left, right)
128106
+ const keyOptions = dictionaryOptions2(
128107
+ context,
128108
+ typeof member.keyEnumId === "string" ? member.keyEnumId : null
127419
128109
  );
128110
+ const entries = orderedDictionaryEntries(body, keyOptions);
127420
128111
  if (entries.length === 0) return "{}";
127421
128112
  return `{
127422
128113
  ${entries.flatMap(
127423
128114
  ([key, id2]) => typeof id2 === "string" ? [
127424
128115
  indentNeoSourceNonEmptyLines(
127425
- `${quote5(key)}: ${emitValue(context, entryMember, id2, {
127426
- environment,
127427
- definitionSite: !context.symbolsByValueId.has(id2),
127428
- // Dictionary keys, like class schema keys, recover entry
127429
- // identity from the owning row. Only list entries need an id.
127430
- writeIdentity: false,
127431
- visited
127432
- })}`,
128116
+ `${emitDictionaryKey(key, keyOptions)}: ${emitValue(
128117
+ context,
128118
+ entryMember,
128119
+ id2,
128120
+ {
128121
+ environment,
128122
+ definitionSite: !context.symbolsByValueId.has(id2),
128123
+ // Dictionary keys, like class schema keys, recover entry
128124
+ // identity from the owning row. Only list entries need an id.
128125
+ writeIdentity: false,
128126
+ visited
128127
+ }
128128
+ )}`,
127433
128129
  2
127434
128130
  )
127435
128131
  ] : []
@@ -127736,6 +128432,32 @@ function enumOptionNames(value) {
127736
128432
  }
127737
128433
  return result;
127738
128434
  }
128435
+ function dictionaryOptions2(context, enumId) {
128436
+ if (enumId === null) return null;
128437
+ const cached = context.dictionaryKeyOptions.get(enumId);
128438
+ if (cached !== void 0) return cached;
128439
+ const schemaEnum = context.enums.get(enumId);
128440
+ if (schemaEnum === void 0) {
128441
+ throw new Error(`Dictionary key enum ${enumId} was not pulled.`);
128442
+ }
128443
+ const options = isObjectRecord2(schemaEnum.options) ? schemaEnum.options : {};
128444
+ const keys = appendMissingKeys(
128445
+ optionalStringArray(schemaEnum.optionKeyOrder),
128446
+ Object.keys(options)
128447
+ );
128448
+ const result = /* @__PURE__ */ new Map();
128449
+ for (const [order, key] of keys.entries()) {
128450
+ const option = options[key];
128451
+ if (!isObjectRecord2(option)) continue;
128452
+ const id2 = typeof option.id === "string" ? option.id : key;
128453
+ const name = typeof option.name === "string" ? option.name : key;
128454
+ const entry = { name, order };
128455
+ result.set(id2, entry);
128456
+ result.set(key, entry);
128457
+ }
128458
+ context.dictionaryKeyOptions.set(enumId, result);
128459
+ return result;
128460
+ }
127739
128461
  function dataById(records2, kind) {
127740
128462
  return new Map(
127741
128463
  [...records2.values()].flatMap(
@@ -127820,6 +128542,7 @@ var init_value_sources = __esm({
127820
128542
  init_local_values();
127821
128543
  init_initializer_reference_spellings();
127822
128544
  init_lower_members();
128545
+ init_dictionary_enum_keys();
127823
128546
  init_lower_variants();
127824
128547
  init_member_kind_type_names();
127825
128548
  init_member_records();
@@ -130942,7 +131665,7 @@ function assignPendingIds(changes, authoredValueSeeds, reconstructed3, localInit
130942
131665
  const instanceRootId = isPendingId(pendingVirtual.instanceRootId) ? assign(pendingVirtual.instanceRootId) : pendingVirtual.instanceRootId;
130943
131666
  const derived = virtualValueId(
130944
131667
  instanceRootId,
130945
- pendingVirtual.sourceIdentity
131668
+ rewriteVirtualSourceIdentity(pendingVirtual.sourceIdentity, assign)
130946
131669
  );
130947
131670
  assigned.set(pendingId2, derived);
130948
131671
  return derived;
@@ -132367,7 +133090,8 @@ async function prepareLocalPushArtifactsV4(workspace, status, onPhase = () => vo
132367
133090
  const localInitializerMaterialization = status.localInitializerMaterialization ?? materializeInitializersLocallyV4({
132368
133091
  workspace,
132369
133092
  changes: pendingTransportChanges,
132370
- authoredValueSeeds: pendingTransportSeeds
133093
+ authoredValueSeeds: pendingTransportSeeds,
133094
+ forceRecompile: options.forceRecompile
132371
133095
  });
132372
133096
  onPhase("Assigning pending value identities\u2026");
132373
133097
  const pendingAssignment = assignPendingIds(
@@ -132410,6 +133134,7 @@ async function prepareLocalPushArtifactsV4(workspace, status, onPhase = () => vo
132410
133134
  changes: transportChanges,
132411
133135
  authoredValueSeeds: transportSeeds,
132412
133136
  initializerMaterialization: pendingAssignment.localInitializerMaterialization ?? { roots: [] },
133137
+ forceRecompile: options.forceRecompile,
132413
133138
  pendingIdAssignments: Object.fromEntries(pendingAssignment.assigned),
132414
133139
  stagedFiles: preparedFiles
132415
133140
  });
@@ -139540,7 +140265,7 @@ var init_registry2 = __esm({
139540
140265
  "schema-contract/registry.mjs"() {
139541
140266
  "use strict";
139542
140267
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
139543
- cliVersion: "0.56.1",
140268
+ cliVersion: "0.57.0",
139544
140269
  projectFileUploadBatchSize: 32,
139545
140270
  documentRecords: {
139546
140271
  member: {
@@ -147361,7 +148086,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
147361
148086
  async function main() {
147362
148087
  const args = parseArgs(process.argv.slice(2));
147363
148088
  if (args.command === "--version") {
147364
- console.log("0.56.1");
148089
+ console.log("0.57.0");
147365
148090
  return;
147366
148091
  }
147367
148092
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {