@neocompose/cli 0.22.7 → 0.23.1

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
@@ -28857,6 +28857,316 @@ var init_contracts = __esm({
28857
28857
  }
28858
28858
  });
28859
28859
 
28860
+ // src/project-sync/merge.ts
28861
+ function threeWayMergeRecord(base, server, local, policy = {}) {
28862
+ const baseRecord = isObjectRecord2(base) ? base : {};
28863
+ const serverRecord = isObjectRecord2(server) ? server : {};
28864
+ const localRecord = isObjectRecord2(local) ? local : {};
28865
+ const comparisonBase = policy.comparison?.base ?? baseRecord;
28866
+ const comparisonServer = policy.comparison?.server ?? serverRecord;
28867
+ const comparisonLocal = policy.comparison?.local ?? localRecord;
28868
+ const merged = {};
28869
+ const conflictFields = [];
28870
+ const keys = /* @__PURE__ */ new Set([
28871
+ ...Object.keys(serverRecord),
28872
+ ...Object.keys(localRecord),
28873
+ ...Object.keys(baseRecord)
28874
+ ]);
28875
+ for (const key of keys) {
28876
+ const rawServerValue = serverRecord[key];
28877
+ const rawLocalValue = localRecord[key];
28878
+ if (policy.serverWinsFields?.has(key) === true) {
28879
+ if (rawServerValue !== void 0) merged[key] = rawServerValue;
28880
+ continue;
28881
+ }
28882
+ const baseValue = comparisonBase[key];
28883
+ const serverValue = comparisonServer[key];
28884
+ const localValue = comparisonLocal[key];
28885
+ const result = mergeValue({
28886
+ rawBase: baseRecord[key],
28887
+ rawServer: rawServerValue,
28888
+ rawLocal: rawLocalValue,
28889
+ base: baseValue,
28890
+ server: serverValue,
28891
+ local: localValue,
28892
+ path: key,
28893
+ recursive: policy.recursive === true
28894
+ });
28895
+ if (result.conflicts.length > 0) {
28896
+ conflictFields.push(...result.conflicts);
28897
+ } else if (result.present) {
28898
+ merged[key] = result.value;
28899
+ }
28900
+ }
28901
+ return { merged, conflictFields };
28902
+ }
28903
+ function mergeValue(args) {
28904
+ if (canonicallyEqual(args.server, args.base)) {
28905
+ return selected(args.rawLocal);
28906
+ }
28907
+ if (canonicallyEqual(args.local, args.base)) {
28908
+ return selected(args.rawServer);
28909
+ }
28910
+ if (canonicallyEqual(args.local, args.server)) {
28911
+ return selected(args.rawLocal);
28912
+ }
28913
+ if (!args.recursive) return conflict(args.path);
28914
+ if (isObjectRecord2(args.rawBase) && isObjectRecord2(args.rawServer) && isObjectRecord2(args.rawLocal)) {
28915
+ const comparisonBase = isObjectRecord2(args.base) ? args.base : args.rawBase;
28916
+ const comparisonServer = isObjectRecord2(args.server) ? args.server : args.rawServer;
28917
+ const comparisonLocal = isObjectRecord2(args.local) ? args.local : args.rawLocal;
28918
+ const value = {};
28919
+ const conflicts = [];
28920
+ const keys = /* @__PURE__ */ new Set([
28921
+ ...Object.keys(args.rawBase),
28922
+ ...Object.keys(args.rawServer),
28923
+ ...Object.keys(args.rawLocal)
28924
+ ]);
28925
+ for (const key of keys) {
28926
+ const nested = mergeValue({
28927
+ rawBase: args.rawBase[key],
28928
+ rawServer: args.rawServer[key],
28929
+ rawLocal: args.rawLocal[key],
28930
+ base: comparisonBase[key],
28931
+ server: comparisonServer[key],
28932
+ local: comparisonLocal[key],
28933
+ path: `${args.path}.${key}`,
28934
+ recursive: true
28935
+ });
28936
+ conflicts.push(...nested.conflicts);
28937
+ if (nested.present) value[key] = nested.value;
28938
+ }
28939
+ return { present: true, value, conflicts };
28940
+ }
28941
+ if (Array.isArray(args.rawBase) && Array.isArray(args.rawServer) && Array.isArray(args.rawLocal)) {
28942
+ return mergeIdentityArray(
28943
+ args.rawBase,
28944
+ args.rawServer,
28945
+ args.rawLocal,
28946
+ args.path
28947
+ );
28948
+ }
28949
+ return conflict(args.path);
28950
+ }
28951
+ function mergeIdentityArray(base, server, local, path) {
28952
+ const baseItems = indexIdentityArray(base);
28953
+ const serverItems = indexIdentityArray(server);
28954
+ const localItems = indexIdentityArray(local);
28955
+ if (baseItems === null || serverItems === null || localItems === null) {
28956
+ return conflict(path);
28957
+ }
28958
+ const retained = /* @__PURE__ */ new Map();
28959
+ const conflicts = [];
28960
+ const ids = /* @__PURE__ */ new Set([
28961
+ ...baseItems.order,
28962
+ ...serverItems.order,
28963
+ ...localItems.order
28964
+ ]);
28965
+ for (const id2 of ids) {
28966
+ const baseHas = baseItems.values.has(id2);
28967
+ const serverHas = serverItems.values.has(id2);
28968
+ const localHas = localItems.values.has(id2);
28969
+ const baseValue = baseItems.values.get(id2);
28970
+ const serverValue = serverItems.values.get(id2);
28971
+ const localValue = localItems.values.get(id2);
28972
+ if (baseHas && !serverHas && !localHas) continue;
28973
+ if (baseHas && !serverHas) {
28974
+ if (canonicallyEqual(localValue, baseValue)) continue;
28975
+ conflicts.push(`${path}[${JSON.stringify(id2)}]`);
28976
+ continue;
28977
+ }
28978
+ if (baseHas && !localHas) {
28979
+ if (canonicallyEqual(serverValue, baseValue)) continue;
28980
+ conflicts.push(`${path}[${JSON.stringify(id2)}]`);
28981
+ continue;
28982
+ }
28983
+ if (!serverHas && localHas) {
28984
+ retained.set(id2, localValue);
28985
+ continue;
28986
+ }
28987
+ if (!localHas && serverHas) {
28988
+ retained.set(id2, serverValue);
28989
+ continue;
28990
+ }
28991
+ const merged = mergeValue({
28992
+ rawBase: baseValue,
28993
+ rawServer: serverValue,
28994
+ rawLocal: localValue,
28995
+ base: baseValue,
28996
+ server: serverValue,
28997
+ local: localValue,
28998
+ path: `${path}[${JSON.stringify(id2)}]`,
28999
+ recursive: true
29000
+ });
29001
+ conflicts.push(...merged.conflicts);
29002
+ if (merged.present) retained.set(id2, merged.value);
29003
+ }
29004
+ if (conflicts.length > 0) return { present: true, value: [], conflicts };
29005
+ const order = mergeIdentityOrder(
29006
+ baseItems.order,
29007
+ serverItems.order,
29008
+ localItems.order,
29009
+ new Set(retained.keys())
29010
+ );
29011
+ if (order === null) return conflict(`${path}.$order`);
29012
+ return {
29013
+ present: true,
29014
+ value: order.map((id2) => retained.get(id2)),
29015
+ conflicts: []
29016
+ };
29017
+ }
29018
+ function indexIdentityArray(values) {
29019
+ const result = /* @__PURE__ */ new Map();
29020
+ const order = [];
29021
+ for (const value of values) {
29022
+ const id2 = identityOf(value);
29023
+ if (id2 === null || result.has(id2)) return null;
29024
+ result.set(id2, value);
29025
+ order.push(id2);
29026
+ }
29027
+ return { order, values: result };
29028
+ }
29029
+ function identityOf(value) {
29030
+ if (typeof value === "string") return value;
29031
+ if (isObjectRecord2(value) && typeof value.id === "string") return value.id;
29032
+ return null;
29033
+ }
29034
+ function mergeIdentityOrder(base, server, local, retained) {
29035
+ const nodes = [...retained];
29036
+ const outgoing = new Map(nodes.map((id2) => [id2, /* @__PURE__ */ new Set()]));
29037
+ const incoming = new Map(nodes.map((id2) => [id2, 0]));
29038
+ for (const order of [server, local]) {
29039
+ const filtered = order.filter((id2) => retained.has(id2));
29040
+ for (let index = 1; index < filtered.length; index += 1) {
29041
+ const before = filtered[index - 1];
29042
+ const after = filtered[index];
29043
+ const edges = outgoing.get(before);
29044
+ if (edges.has(after)) continue;
29045
+ edges.add(after);
29046
+ incoming.set(after, incoming.get(after) + 1);
29047
+ }
29048
+ }
29049
+ const rank = /* @__PURE__ */ new Map();
29050
+ for (const order of [base, server, local]) {
29051
+ for (const id2 of order) {
29052
+ if (!rank.has(id2)) rank.set(id2, rank.size);
29053
+ }
29054
+ }
29055
+ const ready = nodes.filter((id2) => incoming.get(id2) === 0).sort((left, right) => rank.get(left) - rank.get(right));
29056
+ const result = [];
29057
+ while (ready.length > 0) {
29058
+ const id2 = ready.shift();
29059
+ result.push(id2);
29060
+ for (const after of outgoing.get(id2)) {
29061
+ const count = incoming.get(after) - 1;
29062
+ incoming.set(after, count);
29063
+ if (count === 0) {
29064
+ ready.push(after);
29065
+ ready.sort((left, right) => rank.get(left) - rank.get(right));
29066
+ }
29067
+ }
29068
+ }
29069
+ return result.length === nodes.length ? result : null;
29070
+ }
29071
+ function selected(value) {
29072
+ return value === void 0 ? { present: false, conflicts: [] } : { present: true, value, conflicts: [] };
29073
+ }
29074
+ function conflict(path) {
29075
+ return { present: false, conflicts: [path] };
29076
+ }
29077
+ var init_merge = __esm({
29078
+ "src/project-sync/merge.ts"() {
29079
+ "use strict";
29080
+ init_projection();
29081
+ }
29082
+ });
29083
+
29084
+ // src/project-manifest/merge.ts
29085
+ function isSchemaDocumentRecordKind(recordKind) {
29086
+ return Object.hasOwn(SCHEMA_DOCUMENT_FIELD_CONTRACTS, recordKind);
29087
+ }
29088
+ function schemaDocumentSemanticallyEqual(recordKind, left, right) {
29089
+ return canonicallyEqual(
29090
+ normalizeDocumentForComparison(recordKind, left, "left"),
29091
+ normalizeDocumentForComparison(recordKind, right, "right")
29092
+ );
29093
+ }
29094
+ function schemaDocumentAuthoredSemanticallyEqual(recordKind, left, right) {
29095
+ const normalizedLeft = normalizeDocumentForComparison(
29096
+ recordKind,
29097
+ left,
29098
+ "left"
29099
+ );
29100
+ const normalizedRight = normalizeDocumentForComparison(
29101
+ recordKind,
29102
+ right,
29103
+ "right"
29104
+ );
29105
+ return canonicallyEqual(
29106
+ partitionDocumentFields(recordKind, normalizedLeft).authored,
29107
+ partitionDocumentFields(recordKind, normalizedRight).authored
29108
+ );
29109
+ }
29110
+ function mergeSchemaDocumentRecord(recordKind, base, server, local) {
29111
+ const baseRecord = requireDocumentRecord(base, recordKind, "base");
29112
+ const serverRecord = requireDocumentRecord(server, recordKind, "server");
29113
+ const localRecord = requireDocumentRecord(local, recordKind, "local");
29114
+ const contract = SCHEMA_DOCUMENT_FIELD_CONTRACTS[recordKind];
29115
+ return threeWayMergeRecord(baseRecord, serverRecord, localRecord, {
29116
+ comparison: {
29117
+ base: normalizeDocumentForComparison(recordKind, baseRecord, "base"),
29118
+ server: normalizeDocumentForComparison(
29119
+ recordKind,
29120
+ serverRecord,
29121
+ "server"
29122
+ ),
29123
+ local: normalizeDocumentForComparison(recordKind, localRecord, "local")
29124
+ },
29125
+ serverWinsFields: /* @__PURE__ */ new Set([...contract.derived, ...contract.volatile]),
29126
+ recursive: true
29127
+ });
29128
+ }
29129
+ function normalizeDocumentForComparison(recordKind, value, side) {
29130
+ const normalized = normalizeDocumentFields(
29131
+ recordKind,
29132
+ requireDocumentRecord(value, recordKind, side)
29133
+ );
29134
+ if (recordKind === "class") {
29135
+ materializeDeclarationOrder(normalized, "schema", "schemaKeyOrder");
29136
+ } else if (recordKind === "interface") {
29137
+ materializeDeclarationOrder(normalized, "members", "memberKeyOrder");
29138
+ } else if (recordKind === "enum") {
29139
+ materializeDeclarationOrder(normalized, "options", "optionKeyOrder");
29140
+ }
29141
+ return normalized;
29142
+ }
29143
+ function materializeDeclarationOrder(value, recordField, orderField) {
29144
+ const record3 = value[recordField];
29145
+ if (!isObjectRecord2(record3)) return;
29146
+ const explicit = Array.isArray(value[orderField]) ? value[orderField].filter(
29147
+ (entry) => typeof entry === "string" && Object.hasOwn(record3, entry)
29148
+ ) : [];
29149
+ const seen = new Set(explicit);
29150
+ value[orderField] = [
29151
+ ...explicit,
29152
+ ...Object.keys(record3).filter((key) => !seen.has(key))
29153
+ ];
29154
+ }
29155
+ function requireDocumentRecord(value, recordKind, side) {
29156
+ if (isObjectRecord2(value)) return value;
29157
+ throw new Error(
29158
+ `Schema ${recordKind} ${side} document must be an object for semantic merge.`
29159
+ );
29160
+ }
29161
+ var init_merge2 = __esm({
29162
+ "src/project-manifest/merge.ts"() {
29163
+ "use strict";
29164
+ init_merge();
29165
+ init_projection();
29166
+ init_contracts();
29167
+ }
29168
+ });
29169
+
28860
29170
  // src/project-manifest/adapters.ts
28861
29171
  function createSyntheticDocumentSource(recordKind, recordId, symbolKind) {
28862
29172
  const encodedKind = encodeURIComponent(recordKind);
@@ -28897,7 +29207,13 @@ function composeDocumentRecord(recordKind, recordId, authoredFields, baseRecord)
28897
29207
  }
28898
29208
  assertKnownDocumentFields(recordKind, baseRecord.data);
28899
29209
  const base = partitionDocumentFields(recordKind, baseRecord.data);
28900
- Object.assign(data, base.derived, base.volatile);
29210
+ const invalidatesDerivedConstructor = recordKind === "constructor" && !schemaDocumentAuthoredSemanticallyEqual(
29211
+ recordKind,
29212
+ baseRecord.data,
29213
+ normalizedAuthored
29214
+ );
29215
+ if (!invalidatesDerivedConstructor) Object.assign(data, base.derived);
29216
+ Object.assign(data, base.volatile);
28901
29217
  }
28902
29218
  if (recordKind === "member" && data.isReadOnly === false && !Object.prototype.hasOwnProperty.call(baseRecord?.data ?? {}, "isReadOnly")) {
28903
29219
  delete data.isReadOnly;
@@ -28921,6 +29237,7 @@ var init_adapters = __esm({
28921
29237
  "src/project-manifest/adapters.ts"() {
28922
29238
  "use strict";
28923
29239
  init_contracts();
29240
+ init_merge2();
28924
29241
  DEFAULT_DOCUMENT_TO_MANIFEST_CONTEXT = {
28925
29242
  sourceForRecord: createSyntheticDocumentSource
28926
29243
  };
@@ -33797,316 +34114,6 @@ var init_document_adapters = __esm({
33797
34114
  }
33798
34115
  });
33799
34116
 
33800
- // src/project-sync/merge.ts
33801
- function threeWayMergeRecord(base, server, local, policy = {}) {
33802
- const baseRecord = isObjectRecord2(base) ? base : {};
33803
- const serverRecord = isObjectRecord2(server) ? server : {};
33804
- const localRecord = isObjectRecord2(local) ? local : {};
33805
- const comparisonBase = policy.comparison?.base ?? baseRecord;
33806
- const comparisonServer = policy.comparison?.server ?? serverRecord;
33807
- const comparisonLocal = policy.comparison?.local ?? localRecord;
33808
- const merged = {};
33809
- const conflictFields = [];
33810
- const keys = /* @__PURE__ */ new Set([
33811
- ...Object.keys(serverRecord),
33812
- ...Object.keys(localRecord),
33813
- ...Object.keys(baseRecord)
33814
- ]);
33815
- for (const key of keys) {
33816
- const rawServerValue = serverRecord[key];
33817
- const rawLocalValue = localRecord[key];
33818
- if (policy.serverWinsFields?.has(key) === true) {
33819
- if (rawServerValue !== void 0) merged[key] = rawServerValue;
33820
- continue;
33821
- }
33822
- const baseValue = comparisonBase[key];
33823
- const serverValue = comparisonServer[key];
33824
- const localValue = comparisonLocal[key];
33825
- const result = mergeValue({
33826
- rawBase: baseRecord[key],
33827
- rawServer: rawServerValue,
33828
- rawLocal: rawLocalValue,
33829
- base: baseValue,
33830
- server: serverValue,
33831
- local: localValue,
33832
- path: key,
33833
- recursive: policy.recursive === true
33834
- });
33835
- if (result.conflicts.length > 0) {
33836
- conflictFields.push(...result.conflicts);
33837
- } else if (result.present) {
33838
- merged[key] = result.value;
33839
- }
33840
- }
33841
- return { merged, conflictFields };
33842
- }
33843
- function mergeValue(args) {
33844
- if (canonicallyEqual(args.server, args.base)) {
33845
- return selected(args.rawLocal);
33846
- }
33847
- if (canonicallyEqual(args.local, args.base)) {
33848
- return selected(args.rawServer);
33849
- }
33850
- if (canonicallyEqual(args.local, args.server)) {
33851
- return selected(args.rawLocal);
33852
- }
33853
- if (!args.recursive) return conflict(args.path);
33854
- if (isObjectRecord2(args.rawBase) && isObjectRecord2(args.rawServer) && isObjectRecord2(args.rawLocal)) {
33855
- const comparisonBase = isObjectRecord2(args.base) ? args.base : args.rawBase;
33856
- const comparisonServer = isObjectRecord2(args.server) ? args.server : args.rawServer;
33857
- const comparisonLocal = isObjectRecord2(args.local) ? args.local : args.rawLocal;
33858
- const value = {};
33859
- const conflicts = [];
33860
- const keys = /* @__PURE__ */ new Set([
33861
- ...Object.keys(args.rawBase),
33862
- ...Object.keys(args.rawServer),
33863
- ...Object.keys(args.rawLocal)
33864
- ]);
33865
- for (const key of keys) {
33866
- const nested = mergeValue({
33867
- rawBase: args.rawBase[key],
33868
- rawServer: args.rawServer[key],
33869
- rawLocal: args.rawLocal[key],
33870
- base: comparisonBase[key],
33871
- server: comparisonServer[key],
33872
- local: comparisonLocal[key],
33873
- path: `${args.path}.${key}`,
33874
- recursive: true
33875
- });
33876
- conflicts.push(...nested.conflicts);
33877
- if (nested.present) value[key] = nested.value;
33878
- }
33879
- return { present: true, value, conflicts };
33880
- }
33881
- if (Array.isArray(args.rawBase) && Array.isArray(args.rawServer) && Array.isArray(args.rawLocal)) {
33882
- return mergeIdentityArray(
33883
- args.rawBase,
33884
- args.rawServer,
33885
- args.rawLocal,
33886
- args.path
33887
- );
33888
- }
33889
- return conflict(args.path);
33890
- }
33891
- function mergeIdentityArray(base, server, local, path) {
33892
- const baseItems = indexIdentityArray(base);
33893
- const serverItems = indexIdentityArray(server);
33894
- const localItems = indexIdentityArray(local);
33895
- if (baseItems === null || serverItems === null || localItems === null) {
33896
- return conflict(path);
33897
- }
33898
- const retained = /* @__PURE__ */ new Map();
33899
- const conflicts = [];
33900
- const ids = /* @__PURE__ */ new Set([
33901
- ...baseItems.order,
33902
- ...serverItems.order,
33903
- ...localItems.order
33904
- ]);
33905
- for (const id2 of ids) {
33906
- const baseHas = baseItems.values.has(id2);
33907
- const serverHas = serverItems.values.has(id2);
33908
- const localHas = localItems.values.has(id2);
33909
- const baseValue = baseItems.values.get(id2);
33910
- const serverValue = serverItems.values.get(id2);
33911
- const localValue = localItems.values.get(id2);
33912
- if (baseHas && !serverHas && !localHas) continue;
33913
- if (baseHas && !serverHas) {
33914
- if (canonicallyEqual(localValue, baseValue)) continue;
33915
- conflicts.push(`${path}[${JSON.stringify(id2)}]`);
33916
- continue;
33917
- }
33918
- if (baseHas && !localHas) {
33919
- if (canonicallyEqual(serverValue, baseValue)) continue;
33920
- conflicts.push(`${path}[${JSON.stringify(id2)}]`);
33921
- continue;
33922
- }
33923
- if (!serverHas && localHas) {
33924
- retained.set(id2, localValue);
33925
- continue;
33926
- }
33927
- if (!localHas && serverHas) {
33928
- retained.set(id2, serverValue);
33929
- continue;
33930
- }
33931
- const merged = mergeValue({
33932
- rawBase: baseValue,
33933
- rawServer: serverValue,
33934
- rawLocal: localValue,
33935
- base: baseValue,
33936
- server: serverValue,
33937
- local: localValue,
33938
- path: `${path}[${JSON.stringify(id2)}]`,
33939
- recursive: true
33940
- });
33941
- conflicts.push(...merged.conflicts);
33942
- if (merged.present) retained.set(id2, merged.value);
33943
- }
33944
- if (conflicts.length > 0) return { present: true, value: [], conflicts };
33945
- const order = mergeIdentityOrder(
33946
- baseItems.order,
33947
- serverItems.order,
33948
- localItems.order,
33949
- new Set(retained.keys())
33950
- );
33951
- if (order === null) return conflict(`${path}.$order`);
33952
- return {
33953
- present: true,
33954
- value: order.map((id2) => retained.get(id2)),
33955
- conflicts: []
33956
- };
33957
- }
33958
- function indexIdentityArray(values) {
33959
- const result = /* @__PURE__ */ new Map();
33960
- const order = [];
33961
- for (const value of values) {
33962
- const id2 = identityOf(value);
33963
- if (id2 === null || result.has(id2)) return null;
33964
- result.set(id2, value);
33965
- order.push(id2);
33966
- }
33967
- return { order, values: result };
33968
- }
33969
- function identityOf(value) {
33970
- if (typeof value === "string") return value;
33971
- if (isObjectRecord2(value) && typeof value.id === "string") return value.id;
33972
- return null;
33973
- }
33974
- function mergeIdentityOrder(base, server, local, retained) {
33975
- const nodes = [...retained];
33976
- const outgoing = new Map(nodes.map((id2) => [id2, /* @__PURE__ */ new Set()]));
33977
- const incoming = new Map(nodes.map((id2) => [id2, 0]));
33978
- for (const order of [server, local]) {
33979
- const filtered = order.filter((id2) => retained.has(id2));
33980
- for (let index = 1; index < filtered.length; index += 1) {
33981
- const before = filtered[index - 1];
33982
- const after = filtered[index];
33983
- const edges = outgoing.get(before);
33984
- if (edges.has(after)) continue;
33985
- edges.add(after);
33986
- incoming.set(after, incoming.get(after) + 1);
33987
- }
33988
- }
33989
- const rank = /* @__PURE__ */ new Map();
33990
- for (const order of [base, server, local]) {
33991
- for (const id2 of order) {
33992
- if (!rank.has(id2)) rank.set(id2, rank.size);
33993
- }
33994
- }
33995
- const ready = nodes.filter((id2) => incoming.get(id2) === 0).sort((left, right) => rank.get(left) - rank.get(right));
33996
- const result = [];
33997
- while (ready.length > 0) {
33998
- const id2 = ready.shift();
33999
- result.push(id2);
34000
- for (const after of outgoing.get(id2)) {
34001
- const count = incoming.get(after) - 1;
34002
- incoming.set(after, count);
34003
- if (count === 0) {
34004
- ready.push(after);
34005
- ready.sort((left, right) => rank.get(left) - rank.get(right));
34006
- }
34007
- }
34008
- }
34009
- return result.length === nodes.length ? result : null;
34010
- }
34011
- function selected(value) {
34012
- return value === void 0 ? { present: false, conflicts: [] } : { present: true, value, conflicts: [] };
34013
- }
34014
- function conflict(path) {
34015
- return { present: false, conflicts: [path] };
34016
- }
34017
- var init_merge = __esm({
34018
- "src/project-sync/merge.ts"() {
34019
- "use strict";
34020
- init_projection();
34021
- }
34022
- });
34023
-
34024
- // src/project-manifest/merge.ts
34025
- function isSchemaDocumentRecordKind(recordKind) {
34026
- return Object.hasOwn(SCHEMA_DOCUMENT_FIELD_CONTRACTS, recordKind);
34027
- }
34028
- function schemaDocumentSemanticallyEqual(recordKind, left, right) {
34029
- return canonicallyEqual(
34030
- normalizeDocumentForComparison(recordKind, left, "left"),
34031
- normalizeDocumentForComparison(recordKind, right, "right")
34032
- );
34033
- }
34034
- function schemaDocumentAuthoredSemanticallyEqual(recordKind, left, right) {
34035
- const normalizedLeft = normalizeDocumentForComparison(
34036
- recordKind,
34037
- left,
34038
- "left"
34039
- );
34040
- const normalizedRight = normalizeDocumentForComparison(
34041
- recordKind,
34042
- right,
34043
- "right"
34044
- );
34045
- return canonicallyEqual(
34046
- partitionDocumentFields(recordKind, normalizedLeft).authored,
34047
- partitionDocumentFields(recordKind, normalizedRight).authored
34048
- );
34049
- }
34050
- function mergeSchemaDocumentRecord(recordKind, base, server, local) {
34051
- const baseRecord = requireDocumentRecord(base, recordKind, "base");
34052
- const serverRecord = requireDocumentRecord(server, recordKind, "server");
34053
- const localRecord = requireDocumentRecord(local, recordKind, "local");
34054
- const contract = SCHEMA_DOCUMENT_FIELD_CONTRACTS[recordKind];
34055
- return threeWayMergeRecord(baseRecord, serverRecord, localRecord, {
34056
- comparison: {
34057
- base: normalizeDocumentForComparison(recordKind, baseRecord, "base"),
34058
- server: normalizeDocumentForComparison(
34059
- recordKind,
34060
- serverRecord,
34061
- "server"
34062
- ),
34063
- local: normalizeDocumentForComparison(recordKind, localRecord, "local")
34064
- },
34065
- serverWinsFields: /* @__PURE__ */ new Set([...contract.derived, ...contract.volatile]),
34066
- recursive: true
34067
- });
34068
- }
34069
- function normalizeDocumentForComparison(recordKind, value, side) {
34070
- const normalized = normalizeDocumentFields(
34071
- recordKind,
34072
- requireDocumentRecord(value, recordKind, side)
34073
- );
34074
- if (recordKind === "class") {
34075
- materializeDeclarationOrder(normalized, "schema", "schemaKeyOrder");
34076
- } else if (recordKind === "interface") {
34077
- materializeDeclarationOrder(normalized, "members", "memberKeyOrder");
34078
- } else if (recordKind === "enum") {
34079
- materializeDeclarationOrder(normalized, "options", "optionKeyOrder");
34080
- }
34081
- return normalized;
34082
- }
34083
- function materializeDeclarationOrder(value, recordField, orderField) {
34084
- const record3 = value[recordField];
34085
- if (!isObjectRecord2(record3)) return;
34086
- const explicit = Array.isArray(value[orderField]) ? value[orderField].filter(
34087
- (entry) => typeof entry === "string" && Object.hasOwn(record3, entry)
34088
- ) : [];
34089
- const seen = new Set(explicit);
34090
- value[orderField] = [
34091
- ...explicit,
34092
- ...Object.keys(record3).filter((key) => !seen.has(key))
34093
- ];
34094
- }
34095
- function requireDocumentRecord(value, recordKind, side) {
34096
- if (isObjectRecord2(value)) return value;
34097
- throw new Error(
34098
- `Schema ${recordKind} ${side} document must be an object for semantic merge.`
34099
- );
34100
- }
34101
- var init_merge2 = __esm({
34102
- "src/project-manifest/merge.ts"() {
34103
- "use strict";
34104
- init_merge();
34105
- init_projection();
34106
- init_contracts();
34107
- }
34108
- });
34109
-
34110
34117
  // src/project-manifest/index.ts
34111
34118
  var init_project_manifest = __esm({
34112
34119
  "src/project-manifest/index.ts"() {
@@ -35135,6 +35142,12 @@ function isNSPointerVariable(value) {
35135
35142
  const v = value;
35136
35143
  return v?.type === "variable" /* variable */ && typeof v?.variableId === "string";
35137
35144
  }
35145
+ function isNSPointerStaticMember(value) {
35146
+ const v = value;
35147
+ if (v?.type !== "staticMember" /* staticMember */) return false;
35148
+ if (typeof v.memberId !== "string") return false;
35149
+ return v.memberId.length > 0;
35150
+ }
35138
35151
  function isNSPointerValue(value) {
35139
35152
  const v = value;
35140
35153
  return v?.type === "value" /* value */ && isNSValue(v?.value);
@@ -35260,7 +35273,7 @@ function isNSPointerFunctionErrorCheck(value) {
35260
35273
  return isNSFunctionErrorCheckMode(v.mode);
35261
35274
  }
35262
35275
  function isNSPointer(value) {
35263
- return isNSPointerReference(value) || isNSPointerVariable(value) || isNSPointerValue(value) || isNSPointerOperation(value) || isNSPointerFunction(value) || isNSPointerKeyOf(value) || isNSPointerListLiteral(value) || isNSPointerDictLiteral(value) || isNSPointerForceUnwrap(value) || isNSPointerIsCheck(value) || isNSPointerCallGetter(value) || isNSPointerCoalesce(value) || isNSPointerToBool(value) || isNSPointerStringify(value) || isNSPointerCallFunction(value) || isNSPointerCallDelegate(value) || isNSPointerFunctionErrorCheck(value);
35276
+ return isNSPointerReference(value) || isNSPointerVariable(value) || isNSPointerStaticMember(value) || isNSPointerValue(value) || isNSPointerOperation(value) || isNSPointerFunction(value) || isNSPointerKeyOf(value) || isNSPointerListLiteral(value) || isNSPointerDictLiteral(value) || isNSPointerForceUnwrap(value) || isNSPointerIsCheck(value) || isNSPointerCallGetter(value) || isNSPointerCoalesce(value) || isNSPointerToBool(value) || isNSPointerStringify(value) || isNSPointerCallFunction(value) || isNSPointerCallDelegate(value) || isNSPointerFunctionErrorCheck(value);
35264
35277
  }
35265
35278
  function isNSPointers(value) {
35266
35279
  return Array.isArray(value) && value.every(isNSPointer);
@@ -40714,20 +40727,25 @@ function isValidEnumOptionId(id2) {
40714
40727
  if (typeof id2 !== "string" || id2.length === 0) return false;
40715
40728
  return OPTION_ID_REGEX.test(withoutSystemRecordIdPrefix(id2));
40716
40729
  }
40730
+ function isProspectiveEnumOptionId(id2) {
40731
+ if (typeof id2 !== "string" || id2.length === 0) return false;
40732
+ if (isPendingId(id2)) return true;
40733
+ return isValidEnumOptionId(id2);
40734
+ }
40717
40735
  function isValidEnumOptionName(name) {
40718
40736
  return isValidSchemaAuthoredIdentifier(name);
40719
40737
  }
40720
- function isEnumOption(value) {
40738
+ function isEnumOptionWithIds(value, isOptionId) {
40721
40739
  const v = value;
40722
- return !!v && isValidDocsText(v.docsText) && typeof v.text === "string" && typeof v.id === "string" && isValidEnumOptionId(v.id) && typeof v.name === "string" && isValidEnumOptionName(v.name);
40740
+ return !!v && isValidDocsText(v.docsText) && typeof v.text === "string" && typeof v.id === "string" && isOptionId(v.id) && typeof v.name === "string" && isValidEnumOptionName(v.name);
40723
40741
  }
40724
- function isEnumOptionsRecord(value) {
40742
+ function isEnumOptionsRecordWithIds(value, isOptionId) {
40725
40743
  if (value === null || value === void 0) return false;
40726
40744
  if (typeof value !== "object") return false;
40727
40745
  if (Array.isArray(value)) return false;
40728
40746
  for (const [k, v] of Object.entries(value)) {
40729
- if (!isValidEnumOptionId(k)) return false;
40730
- if (!isEnumOption(v)) return false;
40747
+ if (!isOptionId(k)) return false;
40748
+ if (!isEnumOptionWithIds(v, isOptionId)) return false;
40731
40749
  if (v.id !== k) return false;
40732
40750
  }
40733
40751
  return true;
@@ -40737,12 +40755,12 @@ function isOptionalOptionKeyOrder(value) {
40737
40755
  if (!Array.isArray(value)) return false;
40738
40756
  return value.every((key) => typeof key === "string");
40739
40757
  }
40740
- function isEnumBase(value) {
40758
+ function isEnumBaseWithIds(value, isOptionId) {
40741
40759
  const v = value;
40742
40760
  if (!v) return false;
40743
40761
  if (typeof v.name !== "string") return false;
40744
40762
  if (!isValidDocsText(v.docsText)) return false;
40745
- if (!isEnumOptionsRecord(v.options)) return false;
40763
+ if (!isEnumOptionsRecordWithIds(v.options, isOptionId)) return false;
40746
40764
  if (!isOptionalOptionKeyOrder(v.optionKeyOrder)) return false;
40747
40765
  if (v.system !== void 0 && v.system !== null) {
40748
40766
  return isSystemMetadata(v.system);
@@ -40767,17 +40785,24 @@ function getEnumOptionKeyOrder(enumDef) {
40767
40785
  }
40768
40786
  return result;
40769
40787
  }
40770
- function isEnumProps(value) {
40788
+ function isEnumPropsWithIds(value, isOptionId) {
40771
40789
  const v = value;
40772
- return isEnumBase(value) && isWithId(value) && typeof v?.projectId === "string" && isEpochMillis(v?.createdAt) && isEpochMillis(v?.updatedAt);
40790
+ return isEnumBaseWithIds(value, isOptionId) && isWithId(value) && typeof v?.projectId === "string" && isEpochMillis(v?.createdAt) && isEpochMillis(v?.updatedAt);
40791
+ }
40792
+ function isEnumProps(value) {
40793
+ return isEnumPropsWithIds(value, isValidEnumOptionId);
40773
40794
  }
40774
40795
  function isEnum(value) {
40775
40796
  return isEnumProps(value);
40776
40797
  }
40798
+ function isProspectiveEnum(value) {
40799
+ return isEnumPropsWithIds(value, isProspectiveEnumOptionId);
40800
+ }
40777
40801
  var OPTION_ID_REGEX;
40778
40802
  var init_enum_types = __esm({
40779
40803
  "../src/models/enum/enum-types.ts"() {
40780
40804
  "use strict";
40805
+ init_src();
40781
40806
  init_core();
40782
40807
  init_schema_identifiers();
40783
40808
  init_system_record_id();
@@ -43144,12 +43169,10 @@ ${prefix}${renderType(context, member.returnType)} ${member.name}${body}`;
43144
43169
  (argument2) => `${renderType(context, argument2.type)} ${argument2.name}`
43145
43170
  ).join(", ")})`;
43146
43171
  const tracked = member.kind === "scriptFunction" ? member.script?.sourceText ?? uiFunctionSource(context, member) : null;
43147
- const body = tracked ? extractBody(tracked) ?? `{
43148
- ${indentNeoSourceNonEmptyLines(tracked.trim(), 2)}
43149
- }` : null;
43172
+ const body = tracked === null ? null : emitFunctionBody(tracked);
43150
43173
  const abstractContract = member.modifier === "abstract" || member.modifier === "abstractOverride";
43151
43174
  return `${annotations.join("\n")}
43152
- ${body ? `${signature} ${body}` : abstractContract ? `${signature};` : `native ${signature};`}`;
43175
+ ${body !== null ? `${signature} ${body}` : abstractContract ? `${signature};` : `native ${signature};`}`;
43153
43176
  }
43154
43177
  const type = renderMemberType(context, member, enclosingClassId);
43155
43178
  const initializer = initDefaultSource(member) ?? (member.isStatic ? context.staticInitializers.get(member.id) : void 0) ?? context.defaultInitializers.get(member.id) ?? renderDefault(context, member);
@@ -43951,10 +43974,12 @@ function systemAnnotation2(system) {
43951
43974
  ];
43952
43975
  return `@system(${args.join(", ")})`;
43953
43976
  }
43954
- function extractBody(source) {
43955
- const start = source.indexOf("{");
43956
- const end = source.lastIndexOf("}");
43957
- return start >= 0 && end > start ? source.slice(start, end + 1).trim() : null;
43977
+ function emitFunctionBody(sourceText) {
43978
+ const code = sourceText.trim();
43979
+ if (code.length === 0) return "{\n}";
43980
+ return `{
43981
+ ${indentNeoSourceNonEmptyLines(code, 2)}
43982
+ }`;
43958
43983
  }
43959
43984
  function id(value) {
43960
43985
  return `@id(${quote(value)})
@@ -48226,6 +48251,7 @@ function initializerRequiresEvaluation(index, expression, targetClassName, runti
48226
48251
  return true;
48227
48252
  }
48228
48253
  if (expression.kind === "call") return !isLiteralCall(expression);
48254
+ if (isEvaluatedOnlyExpression(expression)) return true;
48229
48255
  if (expression.kind !== "new") return false;
48230
48256
  const className = expression.className ?? targetClassName;
48231
48257
  if (!declaresConstructors(index, className)) return false;
@@ -48301,6 +48327,24 @@ function expressionReadsRuntimeIdentifier(expression, runtimeIdentifiers) {
48301
48327
  return false;
48302
48328
  }
48303
48329
  }
48330
+ function isEvaluatedOnlyExpression(expression) {
48331
+ switch (expression.kind) {
48332
+ case "annotated":
48333
+ return isEvaluatedOnlyExpression(expression.expression);
48334
+ case "binary":
48335
+ case "coalesce":
48336
+ case "index":
48337
+ case "is":
48338
+ case "force":
48339
+ case "litInterp":
48340
+ return true;
48341
+ case "unary":
48342
+ if (expression.op !== "-") return true;
48343
+ return isEvaluatedOnlyExpression(expression.operand);
48344
+ default:
48345
+ return false;
48346
+ }
48347
+ }
48304
48348
  function isLiteralCall(expression) {
48305
48349
  if (expression.callee.kind === "ident" && expression.callee.name === "Reference") {
48306
48350
  return true;
@@ -49232,10 +49276,13 @@ function memberCommon(context, ownerClass, declaration, id2, owner, base) {
49232
49276
  accessModifier: owner.kind === "classMember" ? effectiveSourceAccessModifier(declaration.modifiers, "class") : "public",
49233
49277
  modifier: memberModifier3(declaration.modifiers, base?.modifier),
49234
49278
  locked: hasAnnotation2(declaration.annotations, "locked"),
49235
- // Every declaration kind carries a type, and its nullability is the whole
49236
- // of what `required` means. Properties and getters used to fall back to
49237
- // the pulled value, which left a fresh workspace calling them optional.
49238
- required: !declaration.type.nullable,
49279
+ // Every value-bearing declaration carries a type, and its nullability is
49280
+ // the whole of what `required` means. Properties and getters used to fall
49281
+ // back to the pulled value, which left a fresh workspace calling them
49282
+ // optional. A callable owns no value, so `required` is fixed `false`
49283
+ // (nsfunction-member.md §1.2, function-member.md) and the declared
49284
+ // nullability travels in `returnTypeInfo.required` instead.
49285
+ required: declaration.kind === "function" ? false : !declaration.type.nullable,
49239
49286
  defaultValue: null,
49240
49287
  overrideOf: inheritedId,
49241
49288
  system: systemMetadata(declaration.annotations),
@@ -49955,15 +50002,7 @@ function lowerDefault(context, initializer, type, ownerClass, base, memberId, st
49955
50002
  return base?.defaultValue && "serverValueId" in base.defaultValue ? base.defaultValue : null;
49956
50003
  }
49957
50004
  const expression = parseExpression(initializer);
49958
- if (!isStoredDelegateLiteral(type, expression) && initializerRequiresEvaluation(
49959
- context.declaredConstructors,
49960
- expression,
49961
- type.name,
49962
- requiredConstructorParameterNames(
49963
- context.declaredConstructors,
49964
- ownerClass.name
49965
- )
49966
- )) {
50005
+ if (positionRequiresEvaluation(context, expression, type, ownerClass)) {
49967
50006
  return { init: { code: normalizeInitializerSource(initializer) } };
49968
50007
  }
49969
50008
  if (context.rowBackedDefaultMemberIds.has(memberId) && base?.defaultValue && !("serverValueId" in base.defaultValue)) {
@@ -50029,15 +50068,7 @@ function lowerExpressionValue(context, expression, declaredExpected, ownerClass,
50029
50068
  declaredExpected,
50030
50069
  genericEnvironment
50031
50070
  );
50032
- if (!isStoredDelegateLiteral(expected, expression) && initializerRequiresEvaluation(
50033
- context.declaredConstructors,
50034
- expression,
50035
- expected.name,
50036
- requiredConstructorParameterNames(
50037
- context.declaredConstructors,
50038
- ownerClass.name
50039
- )
50040
- )) {
50071
+ if (positionRequiresEvaluation(context, expression, expected, ownerClass)) {
50041
50072
  return null;
50042
50073
  }
50043
50074
  if (expression.kind === "annotated") {
@@ -50116,10 +50147,20 @@ function lowerExpressionValue(context, expression, declaredExpected, ownerClass,
50116
50147
  const valueType = expected.arguments[1] ?? expected;
50117
50148
  const value = {};
50118
50149
  for (const entry of expression.entries) {
50150
+ if (positionRequiresEvaluation(
50151
+ context,
50152
+ entry.key,
50153
+ DICTIONARY_KEY_TYPE,
50154
+ ownerClass
50155
+ )) {
50156
+ throw new Error(
50157
+ `Dictionary key at ${path} is a computed expression. Dictionary keys must be string literals.`
50158
+ );
50159
+ }
50119
50160
  const key = lowerExpressionValue(
50120
50161
  context,
50121
50162
  entry.key,
50122
- { name: "string", nullable: false, arguments: [] },
50163
+ DICTIONARY_KEY_TYPE,
50123
50164
  ownerClass,
50124
50165
  path,
50125
50166
  genericEnvironment,
@@ -50293,6 +50334,18 @@ function lowerExpressionValue(context, expression, declaredExpected, ownerClass,
50293
50334
  );
50294
50335
  }
50295
50336
  }
50337
+ function positionRequiresEvaluation(context, expression, expected, ownerClass) {
50338
+ if (isStoredDelegateLiteral(expected, expression)) return false;
50339
+ return initializerRequiresEvaluation(
50340
+ context.declaredConstructors,
50341
+ expression,
50342
+ expected.name,
50343
+ requiredConstructorParameterNames(
50344
+ context.declaredConstructors,
50345
+ ownerClass.name
50346
+ )
50347
+ );
50348
+ }
50296
50349
  function isStoredDelegateLiteral(type, expression) {
50297
50350
  if (type.name !== "NeoDelegate") return false;
50298
50351
  let current = expression;
@@ -50374,10 +50427,20 @@ function lowerStructuredLeafDefault(context, kind, expression, expectedType, own
50374
50427
  });
50375
50428
  }
50376
50429
  function requiredComponentNumber(context, expression, ownerClass, label, path) {
50430
+ if (positionRequiresEvaluation(
50431
+ context,
50432
+ expression,
50433
+ STRUCTURED_LEAF_COMPONENT_TYPE,
50434
+ ownerClass
50435
+ )) {
50436
+ throw new Error(
50437
+ `${label} has a computed component. Structured leaf components must be numeric literals.`
50438
+ );
50439
+ }
50377
50440
  const value = lowerExpressionValue(
50378
50441
  context,
50379
50442
  expression,
50380
- { name: "float", nullable: false, arguments: [] },
50443
+ STRUCTURED_LEAF_COMPONENT_TYPE,
50381
50444
  ownerClass,
50382
50445
  path
50383
50446
  );
@@ -50965,7 +51028,7 @@ function* zip(left, right) {
50965
51028
  yield [left[index], right[index]];
50966
51029
  }
50967
51030
  }
50968
- var UNSET_LIST_COLUMN_WIDTH, EMPTY_GENERIC_TYPE_ENVIRONMENT, primitiveMemberKinds;
51031
+ var UNSET_LIST_COLUMN_WIDTH, EMPTY_GENERIC_TYPE_ENVIRONMENT, DICTIONARY_KEY_TYPE, STRUCTURED_LEAF_COMPONENT_TYPE, primitiveMemberKinds;
50969
51032
  var init_lower_members = __esm({
50970
51033
  "src/project-source/lower-members.ts"() {
50971
51034
  "use strict";
@@ -50983,6 +51046,16 @@ var init_lower_members = __esm({
50983
51046
  init_key_reference_spelling();
50984
51047
  UNSET_LIST_COLUMN_WIDTH = -1;
50985
51048
  EMPTY_GENERIC_TYPE_ENVIRONMENT = /* @__PURE__ */ new Map();
51049
+ DICTIONARY_KEY_TYPE = {
51050
+ name: "string",
51051
+ nullable: false,
51052
+ arguments: []
51053
+ };
51054
+ STRUCTURED_LEAF_COMPONENT_TYPE = {
51055
+ name: "float",
51056
+ nullable: false,
51057
+ arguments: []
51058
+ };
50986
51059
  primitiveMemberKinds = /* @__PURE__ */ new Set([
50987
51060
  "null",
50988
51061
  "bool",
@@ -55230,6 +55303,16 @@ function liveListIndexRegistry(ctx) {
55230
55303
  liveListIndexesByProject.set(projectKey, created);
55231
55304
  return created;
55232
55305
  }
55306
+ function evaluatorOwnershipCachesForBase(base) {
55307
+ const existing = evaluatorOwnershipCachesByBase.get(base);
55308
+ if (existing !== void 0) return existing;
55309
+ const created = {
55310
+ ownershipRootIdsByRowId: /* @__PURE__ */ new Map(),
55311
+ ownershipDistancesByRowId: /* @__PURE__ */ new Map()
55312
+ };
55313
+ evaluatorOwnershipCachesByBase.set(base, created);
55314
+ return created;
55315
+ }
55233
55316
  function buildEvaluatorBaseIndexes(members, values, valueById = new Map(
55234
55317
  values.map((row) => [row.id, row])
55235
55318
  )) {
@@ -55239,9 +55322,15 @@ function buildEvaluatorBaseIndexes(members, values, valueById = new Map(
55239
55322
  parentLinksByChildId: /* @__PURE__ */ new Map(),
55240
55323
  indexedRowIds: /* @__PURE__ */ new Set(),
55241
55324
  indexedOverlayValues: /* @__PURE__ */ new Map(),
55325
+ indexedOverlayRowCount: 0,
55242
55326
  shadowedBaseRowIds: /* @__PURE__ */ new Set(),
55243
55327
  listIdentityByArray: /* @__PURE__ */ new WeakMap(),
55244
- declaredListByArray: /* @__PURE__ */ new WeakMap()
55328
+ declaredListByArray: /* @__PURE__ */ new WeakMap(),
55329
+ rowsBySourceValueId: /* @__PURE__ */ new Map(),
55330
+ ownershipRootIdsByRowId: /* @__PURE__ */ new Map(),
55331
+ ownershipDistancesByRowId: /* @__PURE__ */ new Map(),
55332
+ ownedValueAttachmentsByValueId: /* @__PURE__ */ new Map(),
55333
+ memberByRowId: /* @__PURE__ */ new Map()
55245
55334
  };
55246
55335
  const membersByValueId = /* @__PURE__ */ new Map();
55247
55336
  for (const member of members) {
@@ -55260,7 +55349,8 @@ function buildEvaluatorBaseIndexes(members, values, valueById = new Map(
55260
55349
  memberByValueId: indexes.memberByValueId,
55261
55350
  membersByValueId,
55262
55351
  parentLinksByChildId: indexes.parentLinksByChildId,
55263
- indexedRowIds: indexes.indexedRowIds
55352
+ indexedRowIds: indexes.indexedRowIds,
55353
+ rowsBySourceValueId: indexes.rowsBySourceValueId
55264
55354
  };
55265
55355
  }
55266
55356
  function evaluatorIndexes(ctx) {
@@ -55271,6 +55361,8 @@ function evaluatorIndexes(ctx) {
55271
55361
  }
55272
55362
  const liveListIndexes = liveListIndexRegistry(ctx);
55273
55363
  const base = ctx.vm.databaseVM?.evaluatorIndexes;
55364
+ const hasLocalRows = ctx.__runtimeSessionValues !== void 0 || ctx.__valueOverlay !== void 0;
55365
+ const sharedOwnershipCaches = base !== void 0 && !hasLocalRows ? evaluatorOwnershipCachesForBase(base) : null;
55274
55366
  const indexes = {
55275
55367
  rowByValueReference: /* @__PURE__ */ new WeakMap(),
55276
55368
  baseRowByValueReference: base?.rowByValueReference,
@@ -55280,10 +55372,20 @@ function evaluatorIndexes(ctx) {
55280
55372
  indexedRowIds: /* @__PURE__ */ new Set(),
55281
55373
  baseIndexedRowIds: base?.indexedRowIds,
55282
55374
  indexedOverlayValues: /* @__PURE__ */ new Map(),
55375
+ indexedOverlayRowCount: 0,
55283
55376
  shadowedBaseRowIds: /* @__PURE__ */ new Set(),
55284
55377
  overlayRevision,
55285
55378
  listIdentityByArray: liveListIndexes?.identity ?? /* @__PURE__ */ new WeakMap(),
55286
- declaredListByArray: liveListIndexes?.declared ?? /* @__PURE__ */ new WeakMap()
55379
+ declaredListByArray: liveListIndexes?.declared ?? /* @__PURE__ */ new WeakMap(),
55380
+ rowsBySourceValueId: /* @__PURE__ */ new Map(),
55381
+ baseRowsBySourceValueId: base?.rowsBySourceValueId,
55382
+ // A base index describes one immutable evaluator document. Getter calls
55383
+ // over that document can safely share the expensive ownership walks. A
55384
+ // runtime/overlay context gets private caches because it shadows edges.
55385
+ ownershipRootIdsByRowId: sharedOwnershipCaches?.ownershipRootIdsByRowId ?? /* @__PURE__ */ new Map(),
55386
+ ownershipDistancesByRowId: sharedOwnershipCaches?.ownershipDistancesByRowId ?? /* @__PURE__ */ new Map(),
55387
+ ownedValueAttachmentsByValueId: /* @__PURE__ */ new Map(),
55388
+ memberByRowId: /* @__PURE__ */ new Map()
55287
55389
  };
55288
55390
  if (base === void 0) {
55289
55391
  for (const member of ctx.vm.members) {
@@ -55308,19 +55410,47 @@ function evaluatorIndexes(ctx) {
55308
55410
  }
55309
55411
  function syncLazyOverlayReferences(indexes, overlay) {
55310
55412
  if (!(overlay instanceof LazyValueOverlay)) return;
55311
- for (const row of overlay.values()) {
55312
- if (indexes.indexedOverlayValues.get(row.id) === row.value) continue;
55413
+ const materializedRows = overlay.materializedRowsSince(
55414
+ indexes.indexedOverlayRowCount
55415
+ );
55416
+ for (const row of materializedRows) {
55313
55417
  indexes.indexedOverlayValues.set(row.id, row.value);
55314
55418
  if (typeof row.value === "object" && row.value !== null) {
55315
55419
  indexes.rowByValueReference.set(row.value, row);
55316
55420
  }
55317
55421
  }
55422
+ indexes.indexedOverlayRowCount += materializedRows.length;
55318
55423
  }
55319
55424
  function indexEvaluatorRow(indexes, row, allowBaseShadow = false) {
55425
+ indexes.ownedValueAttachmentsByValueId.delete(row.id);
55426
+ if (Array.isArray(row.value)) {
55427
+ for (const childId of row.value) {
55428
+ if (typeof childId === "string") {
55429
+ indexes.ownedValueAttachmentsByValueId.delete(childId);
55430
+ }
55431
+ }
55432
+ } else if (typeof row.value === "object" && row.value !== null) {
55433
+ for (const childId of Object.values(row.value)) {
55434
+ if (typeof childId === "string") {
55435
+ indexes.ownedValueAttachmentsByValueId.delete(childId);
55436
+ }
55437
+ }
55438
+ }
55439
+ indexes.ownershipRootIdsByRowId.clear();
55440
+ indexes.ownershipDistancesByRowId.clear();
55441
+ indexes.memberByRowId.clear();
55320
55442
  if (indexes.indexedRowIds.has(row.id) || !allowBaseShadow && indexes.baseIndexedRowIds?.has(row.id) === true) {
55321
55443
  return;
55322
55444
  }
55323
55445
  indexes.indexedRowIds.add(row.id);
55446
+ if (typeof row.sourceValueId === "string") {
55447
+ const rows = indexes.rowsBySourceValueId.get(row.sourceValueId) ?? [];
55448
+ rows.push(row);
55449
+ indexes.rowsBySourceValueId.set(row.sourceValueId, rows);
55450
+ }
55451
+ if (typeof row.containerId === "string") {
55452
+ addEvaluatorParentLink(indexes, row.id, row.containerId, "");
55453
+ }
55324
55454
  if (typeof row.value === "object" && row.value !== null) {
55325
55455
  indexes.rowByValueReference.set(row.value, row);
55326
55456
  }
@@ -55354,6 +55484,102 @@ function evaluatorParentLinks(indexes, childId) {
55354
55484
  if (local.length === 0) return base;
55355
55485
  return [...base, ...local];
55356
55486
  }
55487
+ function evaluatorRowsForSourceValueId(indexes, sourceValueId) {
55488
+ const base = (indexes.baseRowsBySourceValueId?.get(sourceValueId) ?? []).filter((row) => !indexes.shadowedBaseRowIds.has(row.id));
55489
+ const local = indexes.rowsBySourceValueId.get(sourceValueId) ?? [];
55490
+ if (base.length === 0) return local;
55491
+ if (local.length === 0) return base;
55492
+ return [...base, ...local];
55493
+ }
55494
+ function evaluatorOwnershipRootIds(rowId, indexes) {
55495
+ const cached = indexes.ownershipRootIdsByRowId.get(rowId);
55496
+ if (cached !== void 0) return cached;
55497
+ const roots = /* @__PURE__ */ new Set();
55498
+ const visiting = /* @__PURE__ */ new Set();
55499
+ const visit = (currentId) => {
55500
+ if (visiting.has(currentId)) return;
55501
+ visiting.add(currentId);
55502
+ const parents = evaluatorParentLinks(indexes, currentId);
55503
+ if (parents.length === 0) roots.add(currentId);
55504
+ else for (const parent of parents) visit(parent.parentId);
55505
+ visiting.delete(currentId);
55506
+ };
55507
+ visit(rowId);
55508
+ if (roots.size === 0) roots.add(rowId);
55509
+ indexes.ownershipRootIdsByRowId.set(rowId, roots);
55510
+ return roots;
55511
+ }
55512
+ function evaluatorOwnershipDistances(rowId, indexes) {
55513
+ const cached = indexes.ownershipDistancesByRowId.get(rowId);
55514
+ if (cached !== void 0) return cached;
55515
+ const distances = /* @__PURE__ */ new Map([[rowId, 0]]);
55516
+ const pending = [rowId];
55517
+ while (pending.length > 0) {
55518
+ const currentId = pending.shift();
55519
+ if (currentId === void 0) break;
55520
+ const currentDistance = distances.get(currentId);
55521
+ if (currentDistance === void 0) continue;
55522
+ for (const parent of evaluatorParentLinks(indexes, currentId)) {
55523
+ const nextDistance = currentDistance + 1;
55524
+ const previousDistance = distances.get(parent.parentId);
55525
+ if (previousDistance !== void 0 && previousDistance <= nextDistance) {
55526
+ continue;
55527
+ }
55528
+ distances.set(parent.parentId, nextDistance);
55529
+ pending.push(parent.parentId);
55530
+ }
55531
+ }
55532
+ indexes.ownershipDistancesByRowId.set(rowId, distances);
55533
+ return distances;
55534
+ }
55535
+ function resolveRuntimeReferenceRow(sourceValueId, ctx) {
55536
+ const direct = evalValueById(
55537
+ ctx.vm,
55538
+ sourceValueId,
55539
+ ctx.__runtimeSessionValues,
55540
+ ctx.__valueOverlay
55541
+ );
55542
+ const receiver = trackedRowForValueReference(ctx.thisValue, ctx);
55543
+ if (receiver === null) return direct;
55544
+ const indexes = evaluatorIndexes(ctx);
55545
+ const receiverRoots = evaluatorOwnershipRootIds(receiver.id, indexes);
55546
+ const matches = evaluatorRowsForSourceValueId(indexes, sourceValueId).filter(
55547
+ (candidate) => {
55548
+ const candidateRoots = evaluatorOwnershipRootIds(candidate.id, indexes);
55549
+ for (const rootId of candidateRoots) {
55550
+ if (receiverRoots.has(rootId)) return true;
55551
+ }
55552
+ return false;
55553
+ }
55554
+ );
55555
+ if (matches.length === 0) return direct;
55556
+ if (matches.length === 1) return matches[0] ?? direct;
55557
+ const receiverDistances = evaluatorOwnershipDistances(receiver.id, indexes);
55558
+ let nearestDistance = Number.POSITIVE_INFINITY;
55559
+ let nearestMatches = [];
55560
+ for (const candidate of matches) {
55561
+ const candidateDistances = evaluatorOwnershipDistances(
55562
+ candidate.id,
55563
+ indexes
55564
+ );
55565
+ let distance = Number.POSITIVE_INFINITY;
55566
+ for (const [ownerId, receiverDistance] of receiverDistances) {
55567
+ const candidateDistance = candidateDistances.get(ownerId);
55568
+ if (candidateDistance === void 0) continue;
55569
+ distance = Math.min(distance, receiverDistance + candidateDistance);
55570
+ }
55571
+ if (distance < nearestDistance) {
55572
+ nearestDistance = distance;
55573
+ nearestMatches = [candidate];
55574
+ } else if (distance === nearestDistance) {
55575
+ nearestMatches.push(candidate);
55576
+ }
55577
+ }
55578
+ if (nearestMatches.length === 1) return nearestMatches[0] ?? direct;
55579
+ throw new NSGetterRuntimeError(
55580
+ `Value reference '${sourceValueId}' is ambiguous within the constructed object graph.`
55581
+ );
55582
+ }
55357
55583
  function invalidateEvaluatorIndexes(ctx) {
55358
55584
  if (ctx.__valueOverlay instanceof LazyValueOverlay) {
55359
55585
  ctx.__valueOverlay.markMutated();
@@ -55564,6 +55790,8 @@ function withEvaluationRuntime(ctx, writes) {
55564
55790
  ownedValueAttachments: /* @__PURE__ */ new Map(),
55565
55791
  constructionStack: [],
55566
55792
  loopIterations: 0,
55793
+ budgetedConstructedRowIds: /* @__PURE__ */ new Set(),
55794
+ budgetedProducedEntriesByRowId: /* @__PURE__ */ new Map(),
55567
55795
  budget: createExecutionBudget(ctx.executionBudgetLimits)
55568
55796
  },
55569
55797
  __indexes: ctx.__executionState === void 0 || ctx.__valueOverlay === void 0 ? void 0 : ctx.__indexes
@@ -57211,12 +57439,7 @@ function evalPointer(pointer, scope, ctx) {
57211
57439
  return scope.get(pointer.variableId);
57212
57440
  }
57213
57441
  case "reference" /* reference */: {
57214
- const row = evalValueById(
57215
- ctx.vm,
57216
- pointer.valueId,
57217
- ctx.__runtimeSessionValues,
57218
- ctx.__valueOverlay
57219
- );
57442
+ const row = resolveRuntimeReferenceRow(pointer.valueId, ctx);
57220
57443
  if (!row) {
57221
57444
  throw new NSGetterRuntimeError(
57222
57445
  `Missing value reference: ${pointer.valueId}`
@@ -58432,7 +58655,16 @@ function resolveLocalizedRowValueForMember(row, member, ctx) {
58432
58655
  if (member.localizable === false) return value;
58433
58656
  return resolveLocalizedTextId(value, ctx);
58434
58657
  }
58435
- function memberForValueRow(row, ctx, visited = /* @__PURE__ */ new Set()) {
58658
+ function memberForValueRow(row, ctx) {
58659
+ const indexes = evaluatorIndexes(ctx);
58660
+ if (indexes.memberByRowId.has(row.id)) {
58661
+ return indexes.memberByRowId.get(row.id) ?? null;
58662
+ }
58663
+ const member = resolveMemberForValueRow(row, ctx, /* @__PURE__ */ new Set());
58664
+ indexes.memberByRowId.set(row.id, member);
58665
+ return member;
58666
+ }
58667
+ function resolveMemberForValueRow(row, ctx, visited) {
58436
58668
  if (visited.has(row.id)) return null;
58437
58669
  visited.add(row.id);
58438
58670
  const indexes = evaluatorIndexes(ctx);
@@ -58452,7 +58684,11 @@ function memberForValueRow(row, ctx, visited = /* @__PURE__ */ new Set()) {
58452
58684
  ctx.__valueOverlay
58453
58685
  );
58454
58686
  if (parent === null) continue;
58455
- const parentMember = memberForValueRow(parent, ctx, new Set(visited));
58687
+ const parentMember = resolveMemberForValueRow(
58688
+ parent,
58689
+ ctx,
58690
+ new Set(visited)
58691
+ );
58456
58692
  if (parentMember !== null && isMemberList(parentMember)) {
58457
58693
  return evalMemberById(ctx.vm, parentMember.entryMemberId);
58458
58694
  }
@@ -59482,23 +59718,29 @@ function publishConstructedRows(args) {
59482
59718
  "Class construction requires an effect-capable evaluator Session scope."
59483
59719
  );
59484
59720
  }
59721
+ let newlyConstructedRows = 0;
59722
+ let newlyProducedEntries = 0;
59723
+ for (const row of createdValues) {
59724
+ if (!state.budgetedConstructedRowIds.has(row.id)) {
59725
+ state.budgetedConstructedRowIds.add(row.id);
59726
+ newlyConstructedRows += 1;
59727
+ }
59728
+ const currentEntries = Array.isArray(row.value) ? row.value.length : typeof row.value === "object" && row.value !== null ? Object.keys(row.value).length : 0;
59729
+ const priorEntries = state.budgetedProducedEntriesByRowId.get(row.id) ?? 0;
59730
+ if (currentEntries <= priorEntries) continue;
59731
+ newlyProducedEntries += currentEntries - priorEntries;
59732
+ state.budgetedProducedEntriesByRowId.set(row.id, currentEntries);
59733
+ }
59485
59734
  consumeBudget(
59486
59735
  ctx,
59487
59736
  "constructedSessionRows",
59488
- createdValues.length,
59737
+ newlyConstructedRows,
59489
59738
  "constructed Session row"
59490
59739
  );
59491
- let producedEntries = 0;
59492
- for (const row of createdValues) {
59493
- if (Array.isArray(row.value)) producedEntries += row.value.length;
59494
- else if (typeof row.value === "object" && row.value !== null) {
59495
- producedEntries += Object.keys(row.value).length;
59496
- }
59497
- }
59498
59740
  consumeBudget(
59499
59741
  ctx,
59500
59742
  "producedCollectionEntries",
59501
- producedEntries,
59743
+ newlyProducedEntries,
59502
59744
  "produced collection entry"
59503
59745
  );
59504
59746
  const retained = retainedIds;
@@ -60186,15 +60428,16 @@ function evaluateInitializerInContext(init, member, ctx, createdValues, argument
60186
60428
  }
60187
60429
  if (rootRow === null) {
60188
60430
  const existingValueRow = trackedRowForValueReference(result.value, ctx);
60431
+ const existingRuntimeClassId = existingValueRow === null ? null : classIdForValueRow(existingValueRow, ctx) ?? null;
60189
60432
  const existingConstructorRootId = existingValueRow === null ? null : constructorGroupForRow(existingValueRow.id, ctx);
60190
60433
  if (existingValueRow !== null && existingConstructorRootId === existingValueRow.id) {
60191
60434
  return {
60192
60435
  value: result.value,
60193
- classId: existingValueRow.classId ?? null,
60436
+ classId: existingRuntimeClassId,
60194
60437
  existingValueRow
60195
60438
  };
60196
60439
  }
60197
- return { value: result.value, classId: null };
60440
+ return { value: result.value, classId: existingRuntimeClassId };
60198
60441
  }
60199
60442
  ctx.__runtimeSessionValues?.delete(rootRow.id);
60200
60443
  ctx.__executionState?.constructorGroups.delete(rootRow.id);
@@ -60537,6 +60780,9 @@ function assertOwnedValueAttachable(valueId, destination, destinationName2, ctx,
60537
60780
  }
60538
60781
  }
60539
60782
  function currentOwnedValueAttachments(valueId, ctx) {
60783
+ const indexes = evaluatorIndexes(ctx);
60784
+ const cached = indexes.ownedValueAttachmentsByValueId.get(valueId);
60785
+ if (cached !== void 0) return [...cached];
60540
60786
  const found = /* @__PURE__ */ new Map();
60541
60787
  const add = (attachment) => {
60542
60788
  found.set(attachment.identity, attachment);
@@ -60575,9 +60821,7 @@ function currentOwnedValueAttachments(valueId, ctx) {
60575
60821
  }
60576
60822
  }
60577
60823
  const parentIds = new Set(
60578
- evaluatorParentLinks(evaluatorIndexes(ctx), valueId).map(
60579
- (link) => link.parentId
60580
- )
60824
+ evaluatorParentLinks(indexes, valueId).map((link) => link.parentId)
60581
60825
  );
60582
60826
  for (const parentId of parentIds) {
60583
60827
  const parent = evalValueById(
@@ -60588,21 +60832,25 @@ function currentOwnedValueAttachments(valueId, ctx) {
60588
60832
  );
60589
60833
  if (parent === null) continue;
60590
60834
  if (parent.id === valueId) continue;
60591
- let member = activeStaticBindingRoot(parent.id, ctx)?.member ?? memberForValueRow(parent, ctx);
60592
- if (member !== null) {
60593
- try {
60594
- member = resolveMember2(member, ctx.vm.members);
60595
- if (parent.genericBindings !== void 0) {
60596
- member = substituteMember(
60597
- member,
60598
- envFromStamp(parent.genericBindings),
60599
- ctx.vm.members
60600
- );
60835
+ let member = null;
60836
+ let classId = parent.classId;
60837
+ if (classId === void 0) {
60838
+ member = activeStaticBindingRoot(parent.id, ctx)?.member ?? memberForValueRow(parent, ctx);
60839
+ if (member !== null) {
60840
+ try {
60841
+ member = resolveMember2(member, ctx.vm.members);
60842
+ if (parent.genericBindings !== void 0) {
60843
+ member = substituteMember(
60844
+ member,
60845
+ envFromStamp(parent.genericBindings),
60846
+ ctx.vm.members
60847
+ );
60848
+ }
60849
+ } catch {
60601
60850
  }
60602
- } catch {
60603
60851
  }
60852
+ classId = member !== null && isMemberClassBase(member) ? member.classId : void 0;
60604
60853
  }
60605
- const classId = parent.classId ?? (member !== null && isMemberClassBase(member) ? member.classId : void 0);
60606
60854
  if (classId !== void 0 && typeof parent.value === "object" && parent.value !== null && !Array.isArray(parent.value)) {
60607
60855
  for (const [key, childId] of Object.entries(parent.value)) {
60608
60856
  if (childId !== valueId) continue;
@@ -60633,7 +60881,9 @@ function currentOwnedValueAttachments(valueId, ctx) {
60633
60881
  }
60634
60882
  }
60635
60883
  }
60636
- return [...found.values()];
60884
+ const attachments = [...found.values()];
60885
+ indexes.ownedValueAttachmentsByValueId.set(valueId, attachments);
60886
+ return attachments;
60637
60887
  }
60638
60888
  function constructorArgumentStorage(valueId, ctx, visiting = /* @__PURE__ */ new Set()) {
60639
60889
  if (ctx.__runtimeSessionValues?.has(valueId)) return "session" /* Session */;
@@ -61143,13 +61393,15 @@ function cloneClassValueGraph(receiver, expectedClassId, ctx) {
61143
61393
  `Class.Clone source value '${sourceId3}' could not be read.`
61144
61394
  );
61145
61395
  }
61146
- const runtimeClassId = classIdForValueRow(source, ctx);
61147
- if (runtimeClassId === void 0) {
61396
+ const resolvedRuntimeClassId = classIdForValueRow(source, ctx);
61397
+ const runtimeClassId = resolvedRuntimeClassId ?? expectedClassId;
61398
+ if (runtimeClassId !== expectedClassId && !resolveInheritanceChain(runtimeClassId, ctx.vm.classes).some(
61399
+ (candidate) => candidate.id === expectedClassId
61400
+ )) {
61148
61401
  throw new NSGetterRuntimeError(
61149
- `Class.Clone source value '${sourceId3}' has no Class runtime type.`
61402
+ `Class.Clone source value '${sourceId3}' has runtime Class '${runtimeClassId}', which is not assignable to '${expectedClassId}'.`
61150
61403
  );
61151
61404
  }
61152
- void expectedClassId;
61153
61405
  const destination = ctx.__runtimeSessionValues ?? (() => {
61154
61406
  throw new NSGetterRuntimeError(
61155
61407
  "Class.Clone requires an evaluator Session value registry."
@@ -61272,7 +61524,10 @@ function cloneClassValueGraph(receiver, expectedClassId, ctx) {
61272
61524
  return clone;
61273
61525
  };
61274
61526
  const rootMember = memberForValueRow(source, ctx);
61275
- return cloneRow(source, rootMember).value;
61527
+ const typedSource = source.classId === void 0 ? { ...source, classId: runtimeClassId } : source;
61528
+ const clonedRoot = cloneRow(typedSource, rootMember);
61529
+ clonedRoot.classId ??= runtimeClassId;
61530
+ return clonedRoot.value;
61276
61531
  }
61277
61532
  function ownedObjectChildMember(row, sourceMember, key, ctx) {
61278
61533
  if (sourceMember !== null && isMemberDictionary(sourceMember)) {
@@ -61451,7 +61706,7 @@ function pushParams(parent, parameters, positional, isList) {
61451
61706
  }
61452
61707
  return child;
61453
61708
  }
61454
- var DELEGATE_LEXICAL_THIS, DELEGATE_LEXICAL_ROOT, NonCatchableNSGetterRuntimeError, NativeFunctionDelegateUnavailableError, CorruptNeoScriptIRError, NeoScriptResourceLimitError, DEFAULT_NEO_SCRIPT_EXECUTION_BUDGET_LIMITS, liveListIndexesByProject, MAX_CONSTRUCTION_DEPTH, MAX_LOOP_ITERATIONS, LazyValueOverlay, readonlyBindingErrorsByScope, READONLY_FOREACH_BINDING_ERROR, READONLY_CATCH_BINDING_ERROR;
61709
+ var DELEGATE_LEXICAL_THIS, DELEGATE_LEXICAL_ROOT, NonCatchableNSGetterRuntimeError, NativeFunctionDelegateUnavailableError, CorruptNeoScriptIRError, NeoScriptResourceLimitError, DEFAULT_NEO_SCRIPT_EXECUTION_BUDGET_LIMITS, liveListIndexesByProject, evaluatorOwnershipCachesByBase, MAX_CONSTRUCTION_DEPTH, MAX_LOOP_ITERATIONS, LazyValueOverlay, readonlyBindingErrorsByScope, READONLY_FOREACH_BINDING_ERROR, READONLY_CATCH_BINDING_ERROR;
61455
61710
  var init_evaluateNSGetter = __esm({
61456
61711
  "../src/view-models/neoscript-evaluator/evaluateNSGetter.ts"() {
61457
61712
  "use strict";
@@ -61486,10 +61741,11 @@ var init_evaluateNSGetter = __esm({
61486
61741
  workUnits: 1e5,
61487
61742
  collectionVisits: 1e5,
61488
61743
  producedCollectionEntries: 1e4,
61489
- constructedSessionRows: 1e3,
61744
+ constructedSessionRows: 4096,
61490
61745
  producedStringCharacters: 1024 * 1024
61491
61746
  });
61492
61747
  liveListIndexesByProject = /* @__PURE__ */ new WeakMap();
61748
+ evaluatorOwnershipCachesByBase = /* @__PURE__ */ new WeakMap();
61493
61749
  MAX_CONSTRUCTION_DEPTH = 64;
61494
61750
  MAX_LOOP_ITERATIONS = 1e4;
61495
61751
  LazyValueOverlay = class extends Map {
@@ -61499,6 +61755,7 @@ var init_evaluateNSGetter = __esm({
61499
61755
  }
61500
61756
  vm;
61501
61757
  revision = 0;
61758
+ materializedRows = [];
61502
61759
  sourceIndexes;
61503
61760
  sourceValueByClone = /* @__PURE__ */ new WeakMap();
61504
61761
  get(id2) {
@@ -61514,8 +61771,12 @@ var init_evaluateNSGetter = __esm({
61514
61771
  this.sourceValueByClone.set(value, source.value);
61515
61772
  }
61516
61773
  super.set(id2, clone);
61774
+ this.materializedRows.push(clone);
61517
61775
  return clone;
61518
61776
  }
61777
+ materializedRowsSince(index) {
61778
+ return this.materializedRows.slice(index);
61779
+ }
61519
61780
  cloneForValueReference(value) {
61520
61781
  const source = this.ensureSourceIndexes().byReference.get(value);
61521
61782
  return source === void 0 ? void 0 : this.get(source.id)?.value;
@@ -63210,7 +63471,11 @@ function readProjectDocument(value, options = {}) {
63210
63471
  isInternalRecordRelation
63211
63472
  ),
63212
63473
  values: readArrayField(value, "values", isMemberValue),
63213
- enums: readArrayField(value, "enums", isEnum),
63474
+ enums: readArrayField(
63475
+ value,
63476
+ "enums",
63477
+ options.identities === "prospective" ? isProspectiveEnum : isEnum
63478
+ ),
63214
63479
  interfaces: readArrayField(value, "interfaces", isNeoInterface),
63215
63480
  dialogues: readArrayField(value, "dialogues", isDialogue),
63216
63481
  dialogueRecords: readOptionalArrayField(
@@ -72211,6 +72476,145 @@ var init_trusted_commit_verification = __esm({
72211
72476
  });
72212
72477
 
72213
72478
  // ../src/models/classes/world-layer-link-target.ts
72479
+ function validateWorldLayerLinkClassTargets(args) {
72480
+ for (const schemaClass2 of args.classes) {
72481
+ if (args.classIds !== void 0 && !args.classIds.has(schemaClass2.id)) {
72482
+ continue;
72483
+ }
72484
+ const directWorldKind = schemaClass2.system?.worldKind;
72485
+ const isSystemLinkBase = directWorldKind === NeoWorldSystemClassKind.TileLayerLink || directWorldKind === NeoWorldSystemClassKind.ObjectLayerLink;
72486
+ const descriptor = worldLayerLinkTargetDescriptorForClass(
72487
+ schemaClass2.id,
72488
+ args.classes
72489
+ );
72490
+ if (descriptor === null) continue;
72491
+ if (isSystemLinkBase) {
72492
+ if (!schemaClass2.isAbstract) {
72493
+ throw new Error(
72494
+ `System layer-link base class "${schemaClass2.id}" must remain abstract.`
72495
+ );
72496
+ }
72497
+ if (worldLayerLinkTargetRelations(
72498
+ schemaClass2.id,
72499
+ descriptor,
72500
+ args.relations
72501
+ ).length > 0) {
72502
+ throw new Error(
72503
+ `System layer-link base class "${schemaClass2.id}" cannot declare a layer target relation.`
72504
+ );
72505
+ }
72506
+ continue;
72507
+ }
72508
+ if (schemaClass2.isAbstract) continue;
72509
+ resolveWorldLayerLinkTarget({
72510
+ classes: args.classes,
72511
+ linkLabel: `Concrete layer-link class "${schemaClass2.id}"`,
72512
+ relations: args.relations,
72513
+ sourceClassId: schemaClass2.id
72514
+ });
72515
+ }
72516
+ }
72517
+ function worldLayerLinkTargetDescriptorForClass(classId, classes) {
72518
+ const worldKind = resolveWorldSystemClassKind(classId, classes);
72519
+ if (worldKind === NeoWorldSystemClassKind.TileLayerLink) {
72520
+ return {
72521
+ relationKind: InternalRecordRelationKind.WorldTileLayerLinkTarget,
72522
+ targetWorldKind: NeoWorldSystemClassKind.TileLayer
72523
+ };
72524
+ }
72525
+ if (worldKind === NeoWorldSystemClassKind.ObjectLayerLink) {
72526
+ return {
72527
+ relationKind: InternalRecordRelationKind.WorldObjectLayerLinkTarget,
72528
+ targetWorldKind: NeoWorldSystemClassKind.ObjectLayer
72529
+ };
72530
+ }
72531
+ return null;
72532
+ }
72533
+ function worldLayerLinkTargetRelations(classId, descriptor, relations) {
72534
+ return relations.filter(
72535
+ (relation) => relation.relationKind === descriptor.relationKind && relation.sourceRecordKind === ProjectRecordKind.Class && relation.sourceRecordId === classId && relation.targetRecordKind === ProjectRecordKind.Class
72536
+ );
72537
+ }
72538
+ function resolveWorldLayerLinkTarget(args) {
72539
+ const label = args.linkLabel ?? `Layer-link class "${args.sourceClassId}"`;
72540
+ const sourceClass = args.classes.find(
72541
+ (candidate) => candidate.id === args.sourceClassId
72542
+ );
72543
+ if (sourceClass === void 0) {
72544
+ throw new Error(
72545
+ `${label} references missing class "${args.sourceClassId}".`
72546
+ );
72547
+ }
72548
+ if (sourceClass.isAbstract) {
72549
+ throw new Error(
72550
+ `${label} cannot instantiate abstract class "${args.sourceClassId}".`
72551
+ );
72552
+ }
72553
+ const descriptor = worldLayerLinkTargetDescriptorForClass(
72554
+ args.sourceClassId,
72555
+ args.classes
72556
+ );
72557
+ if (descriptor === null) {
72558
+ throw new Error(
72559
+ `${label} class "${args.sourceClassId}" is not a tile/object layer-link class.`
72560
+ );
72561
+ }
72562
+ const effective = resolveEffectiveClassRelations({
72563
+ relationKind: descriptor.relationKind,
72564
+ sourceClassId: args.sourceClassId,
72565
+ relations: args.relations,
72566
+ classes: args.classes
72567
+ });
72568
+ if (effective.length > 1) {
72569
+ throw new Error(
72570
+ `${label} class "${args.sourceClassId}" resolves more than one effective target for relation kind "${descriptor.relationKind}".`
72571
+ );
72572
+ }
72573
+ const relationTarget = effective[0] ?? null;
72574
+ if (relationTarget !== null) {
72575
+ const declarationClass = args.classes.find(
72576
+ (candidate) => candidate.id === relationTarget.declaredSourceRecordId
72577
+ );
72578
+ if (declarationClass?.system?.worldKind === NeoWorldSystemClassKind.TileLayerLink || declarationClass?.system?.worldKind === NeoWorldSystemClassKind.ObjectLayerLink) {
72579
+ throw new Error(
72580
+ `${label} class "${args.sourceClassId}" cannot inherit a layer target relation from system base class "${declarationClass.id}".`
72581
+ );
72582
+ }
72583
+ }
72584
+ if (relationTarget === null) {
72585
+ throw new Error(
72586
+ `${label} class "${args.sourceClassId}" has no effective layer target relation.`
72587
+ );
72588
+ }
72589
+ const targetClassId = relationTarget.targetRecordId;
72590
+ const targetClass = args.classes.find(
72591
+ (candidate) => candidate.id === targetClassId
72592
+ );
72593
+ if (targetClass === void 0) {
72594
+ throw new Error(`${label} targets missing layer class "${targetClassId}".`);
72595
+ }
72596
+ if (targetClass.isAbstract) {
72597
+ throw new Error(
72598
+ `${label} targets abstract layer class "${targetClassId}".`
72599
+ );
72600
+ }
72601
+ const targetWorldKind = resolveWorldSystemClassKind(
72602
+ targetClass.id,
72603
+ args.classes
72604
+ );
72605
+ if (targetWorldKind !== descriptor.targetWorldKind) {
72606
+ throw new Error(
72607
+ `${label} targets class "${targetClassId}" of world kind "${String(targetWorldKind)}"; expected "${descriptor.targetWorldKind}".`
72608
+ );
72609
+ }
72610
+ return {
72611
+ declaredSourceClassId: relationTarget.declaredSourceRecordId,
72612
+ relationIds: relationTarget.relationIds,
72613
+ relationKind: descriptor.relationKind,
72614
+ sourceClassId: args.sourceClassId,
72615
+ targetClassId
72616
+ };
72617
+ }
72214
72618
  var init_world_layer_link_target = __esm({
72215
72619
  "../src/models/classes/world-layer-link-target.ts"() {
72216
72620
  "use strict";
@@ -72221,6 +72625,292 @@ var init_world_layer_link_target = __esm({
72221
72625
  });
72222
72626
 
72223
72627
  // ../src/models/project/world-content-sidecar-validation.ts
72628
+ function validateWorldContentSidecars(args) {
72629
+ const valuesById = new Map(args.values.map((value) => [value.id, value]));
72630
+ const classesById = new Map(
72631
+ args.classes.map((schemaClass2) => [schemaClass2.id, schemaClass2])
72632
+ );
72633
+ const containedIds = containedValueIdsByContainer(args.values);
72634
+ const ownedLinkIds = /* @__PURE__ */ new Map();
72635
+ const gridOwnedLinkIds = /* @__PURE__ */ new Set();
72636
+ const validatedPlacementIds = /* @__PURE__ */ new Set();
72637
+ const reachablePlacementIds = /* @__PURE__ */ new Set();
72638
+ for (const gridValue of args.values) {
72639
+ if (worldKindForValue(gridValue, args.classes) !== NeoWorldSystemClassKind.TileGrid) {
72640
+ continue;
72641
+ }
72642
+ const gridClassId = requiredValueClassId(gridValue, "tile-grid");
72643
+ const gridRecord = valueObjectRecord(gridValue);
72644
+ if (gridRecord === null) continue;
72645
+ const childrenList = referencedValue(
72646
+ gridRecord.Children,
72647
+ valuesById,
72648
+ `Grid value "${gridValue.id}" Children`
72649
+ );
72650
+ if (childrenList === null) continue;
72651
+ const registeredTileLayers = effectiveTargetIds({
72652
+ classes: args.classes,
72653
+ relationKind: InternalRecordRelationKind.WorldGridTileLayer,
72654
+ relations: args.relations,
72655
+ sourceClassId: gridClassId
72656
+ });
72657
+ const registeredObjectLayers = effectiveTargetIds({
72658
+ classes: args.classes,
72659
+ relationKind: InternalRecordRelationKind.WorldGridObjectLayer,
72660
+ relations: args.relations,
72661
+ sourceClassId: gridClassId
72662
+ });
72663
+ const importedTiles = effectiveTargetIds({
72664
+ classes: args.classes,
72665
+ relationKind: InternalRecordRelationKind.WorldGridTileImport,
72666
+ relations: args.relations,
72667
+ sourceClassId: gridClassId
72668
+ });
72669
+ const importedObjects = effectiveTargetIds({
72670
+ classes: args.classes,
72671
+ relationKind: InternalRecordRelationKind.WorldGridObjectImport,
72672
+ relations: args.relations,
72673
+ sourceClassId: gridClassId
72674
+ });
72675
+ const overrideOwnerByLayerKey = /* @__PURE__ */ new Map();
72676
+ for (const linkId of containmentEntryIds(childrenList, containedIds)) {
72677
+ const linkValue = valuesById.get(linkId);
72678
+ if (linkValue === void 0) {
72679
+ throw new Error(
72680
+ `Grid value "${gridValue.id}" Children references missing value "${linkId}".`
72681
+ );
72682
+ }
72683
+ const linkKind = worldKindForValue(linkValue, args.classes);
72684
+ if (linkKind !== NeoWorldSystemClassKind.TileLayerLink && linkKind !== NeoWorldSystemClassKind.ObjectLayerLink) {
72685
+ continue;
72686
+ }
72687
+ const linkRecord = valueObjectRecord(linkValue);
72688
+ if (linkRecord === null) continue;
72689
+ gridOwnedLinkIds.add(linkValue.id);
72690
+ const placementListKey = linkKind === NeoWorldSystemClassKind.TileLayerLink ? "Tiles" : "Objects";
72691
+ const placementList = referencedValue(
72692
+ linkRecord[placementListKey],
72693
+ valuesById,
72694
+ `Layer link value "${linkValue.id}" ${placementListKey}`
72695
+ );
72696
+ const placementIds = placementList === null ? [] : containmentEntryIds(placementList, containedIds);
72697
+ for (const placementId of placementIds) {
72698
+ reachablePlacementIds.add(placementId);
72699
+ }
72700
+ const linkClassId = requiredValueClassId(linkValue, "layer-link");
72701
+ const layerClassId = resolveWorldLayerLinkTarget({
72702
+ classes: args.classes,
72703
+ linkLabel: `Layer link value "${linkValue.id}"`,
72704
+ relations: args.relations,
72705
+ sourceClassId: linkClassId
72706
+ }).targetClassId;
72707
+ const existingOwner = ownedLinkIds.get(linkValue.id);
72708
+ if (existingOwner !== void 0 && existingOwner !== gridValue.id) {
72709
+ throw new Error(
72710
+ `Layer link value "${linkValue.id}" is owned by both grid values "${existingOwner}" and "${gridValue.id}".`
72711
+ );
72712
+ }
72713
+ ownedLinkIds.set(linkValue.id, gridValue.id);
72714
+ const isTile = linkKind === NeoWorldSystemClassKind.TileLayerLink;
72715
+ const expectedLayerKind = isTile ? NeoWorldSystemClassKind.TileLayer : NeoWorldSystemClassKind.ObjectLayer;
72716
+ assertConcreteWorldClass({
72717
+ classId: layerClassId,
72718
+ classes: args.classes,
72719
+ classesById,
72720
+ expectedKind: expectedLayerKind,
72721
+ label: `Layer link value "${linkValue.id}" target`
72722
+ });
72723
+ const registeredLayers = isTile ? registeredTileLayers : registeredObjectLayers;
72724
+ if (!registeredLayers.has(layerClassId)) {
72725
+ throw new Error(
72726
+ `Layer link value "${linkValue.id}" binds unregistered ${isTile ? "tile" : "object"} layer class "${layerClassId}" on grid value "${gridValue.id}".`
72727
+ );
72728
+ }
72729
+ const layerOverrideValueId = optionalNonEmptyString(
72730
+ linkRecord.layerOverrideValueId
72731
+ );
72732
+ const layerKey = `${isTile ? "tile" : "object"}:${layerClassId}`;
72733
+ if (layerOverrideValueId !== null) {
72734
+ const existingOverrideOwner = overrideOwnerByLayerKey.get(layerKey);
72735
+ if (existingOverrideOwner !== void 0 && existingOverrideOwner !== linkValue.id) {
72736
+ throw new Error(
72737
+ `Grid value "${gridValue.id}" has more than one override-owning ${isTile ? "tile" : "object"} layer link for class "${layerClassId}" ("${existingOverrideOwner}" and "${linkValue.id}"). Source links may share a layer target, but at most one may define layerOverrideValueId.`
72738
+ );
72739
+ }
72740
+ overrideOwnerByLayerKey.set(layerKey, linkValue.id);
72741
+ }
72742
+ validateOwnedSparseValue({
72743
+ classesById,
72744
+ expectedClassId: layerClassId,
72745
+ ownerId: linkValue.id,
72746
+ referenceId: layerOverrideValueId,
72747
+ referenceLabel: `Layer link value "${linkValue.id}" layerOverrideValueId`,
72748
+ valuesById
72749
+ });
72750
+ for (const placementId of placementIds) {
72751
+ const placement = valuesById.get(placementId);
72752
+ if (placement === void 0) {
72753
+ throw new Error(
72754
+ `Layer link value "${linkValue.id}" ${placementListKey} references missing placement "${placementId}".`
72755
+ );
72756
+ }
72757
+ validateWorldPlacementSidecars({
72758
+ classes: args.classes,
72759
+ classesById,
72760
+ importedClassIds: isTile ? importedTiles : importedObjects,
72761
+ isTile,
72762
+ layerClassId,
72763
+ linkValueId: linkValue.id,
72764
+ placement,
72765
+ relations: args.relations,
72766
+ valuesById
72767
+ });
72768
+ validatedPlacementIds.add(placement.id);
72769
+ }
72770
+ }
72771
+ }
72772
+ for (const linkValue of args.values) {
72773
+ if (gridOwnedLinkIds.has(linkValue.id)) continue;
72774
+ const linkKind = worldKindForValue(linkValue, args.classes);
72775
+ if (linkKind !== NeoWorldSystemClassKind.TileLayerLink && linkKind !== NeoWorldSystemClassKind.ObjectLayerLink) {
72776
+ continue;
72777
+ }
72778
+ const linkRecord = valueObjectRecord(linkValue);
72779
+ if (linkRecord === null) continue;
72780
+ const isTile = linkKind === NeoWorldSystemClassKind.TileLayerLink;
72781
+ const linkClassId = requiredValueClassId(linkValue, "layer-link");
72782
+ const layerClassId = resolveWorldLayerLinkTarget({
72783
+ classes: args.classes,
72784
+ linkLabel: `Object-composition layer link value "${linkValue.id}"`,
72785
+ relations: args.relations,
72786
+ sourceClassId: linkClassId
72787
+ }).targetClassId;
72788
+ assertConcreteWorldClass({
72789
+ classId: layerClassId,
72790
+ classes: args.classes,
72791
+ classesById,
72792
+ expectedKind: isTile ? NeoWorldSystemClassKind.TileLayer : NeoWorldSystemClassKind.ObjectLayer,
72793
+ label: `Object-composition layer link value "${linkValue.id}" target`
72794
+ });
72795
+ validateOwnedSparseValue({
72796
+ classesById,
72797
+ expectedClassId: layerClassId,
72798
+ ownerId: linkValue.id,
72799
+ referenceId: optionalNonEmptyString(linkRecord.layerOverrideValueId),
72800
+ referenceLabel: `Object-composition layer link value "${linkValue.id}" layerOverrideValueId`,
72801
+ valuesById
72802
+ });
72803
+ const placementListKey = isTile ? "Tiles" : "Objects";
72804
+ const placementList = referencedValue(
72805
+ linkRecord[placementListKey],
72806
+ valuesById,
72807
+ `Object-composition layer link value "${linkValue.id}" ${placementListKey}`
72808
+ );
72809
+ if (placementList === null) continue;
72810
+ for (const placementId of containmentEntryIds(
72811
+ placementList,
72812
+ containedIds
72813
+ )) {
72814
+ const placement = valuesById.get(placementId);
72815
+ if (placement === void 0) {
72816
+ throw new Error(
72817
+ `Object-composition layer link value "${linkValue.id}" references missing placement "${placementId}".`
72818
+ );
72819
+ }
72820
+ validateWorldPlacementSidecars({
72821
+ classes: args.classes,
72822
+ classesById,
72823
+ importedClassIds: null,
72824
+ isTile,
72825
+ layerClassId,
72826
+ linkValueId: linkValue.id,
72827
+ placement,
72828
+ relations: args.relations,
72829
+ valuesById
72830
+ });
72831
+ reachablePlacementIds.add(placement.id);
72832
+ validatedPlacementIds.add(placement.id);
72833
+ }
72834
+ }
72835
+ for (const value of args.values) {
72836
+ const record3 = valueObjectRecord(value);
72837
+ if (record3 === null) continue;
72838
+ if (optionalNonEmptyString(record3.assetClassId) !== null && !validatedPlacementIds.has(value.id) && !reachablePlacementIds.has(value.id)) {
72839
+ throw new Error(
72840
+ `Class-backed placement value "${value.id}" is not owned by a class-backed layer link.`
72841
+ );
72842
+ }
72843
+ }
72844
+ }
72845
+ function validateWorldPlacementSidecars(args) {
72846
+ const record3 = valueObjectRecord(args.placement);
72847
+ if (record3 === null) {
72848
+ throw new Error(
72849
+ `Placement value "${args.placement.id}" under layer link "${args.linkValueId}" must store a class record.`
72850
+ );
72851
+ }
72852
+ const assetClassId = optionalNonEmptyString(record3.assetClassId);
72853
+ if (assetClassId === null) {
72854
+ throw new Error(
72855
+ `Class-backed placement value "${args.placement.id}" is missing assetClassId.`
72856
+ );
72857
+ }
72858
+ assertConcreteWorldClass({
72859
+ classId: assetClassId,
72860
+ classes: args.classes,
72861
+ classesById: args.classesById,
72862
+ expectedKind: args.isTile ? NeoWorldSystemClassKind.Tile : NeoWorldSystemClassKind.Object,
72863
+ label: `Placement value "${args.placement.id}" assetClassId`
72864
+ });
72865
+ if (args.importedClassIds !== null && !args.importedClassIds.has(assetClassId)) {
72866
+ throw new Error(
72867
+ `Placement value "${args.placement.id}" uses ${args.isTile ? "tile" : "object"} class "${assetClassId}" that is not imported by its grid.`
72868
+ );
72869
+ }
72870
+ const compatibleLayerIds = effectiveTargetIds({
72871
+ classes: args.classes,
72872
+ relationKind: args.isTile ? InternalRecordRelationKind.WorldTileCompatibleLayer : InternalRecordRelationKind.WorldObjectCompatibleLayer,
72873
+ relations: args.relations,
72874
+ sourceClassId: assetClassId
72875
+ });
72876
+ if (!compatibleLayerIds.has(args.layerClassId)) {
72877
+ throw new Error(
72878
+ `Placement value "${args.placement.id}" asset class "${assetClassId}" is not compatible with layer class "${args.layerClassId}".`
72879
+ );
72880
+ }
72881
+ validateOwnedSparseValue({
72882
+ classesById: args.classesById,
72883
+ expectedClassId: assetClassId,
72884
+ ownerId: args.placement.id,
72885
+ referenceId: optionalNonEmptyString(record3.assetValueId),
72886
+ referenceLabel: `Placement value "${args.placement.id}" assetValueId`,
72887
+ valuesById: args.valuesById
72888
+ });
72889
+ }
72890
+ function validateOwnedSparseValue(args) {
72891
+ if (args.referenceId === null) return;
72892
+ const value = args.valuesById.get(args.referenceId);
72893
+ if (value === void 0) {
72894
+ throw new Error(
72895
+ `${args.referenceLabel} references missing value "${args.referenceId}".`
72896
+ );
72897
+ }
72898
+ if (!args.classesById.has(args.expectedClassId)) {
72899
+ throw new Error(
72900
+ `${args.referenceLabel} expects missing class "${args.expectedClassId}".`
72901
+ );
72902
+ }
72903
+ if (value.classId !== args.expectedClassId) {
72904
+ throw new Error(
72905
+ `${args.referenceLabel} references value "${value.id}" with class "${String(value.classId)}", expected "${args.expectedClassId}".`
72906
+ );
72907
+ }
72908
+ if (value.containerId !== args.ownerId) {
72909
+ throw new Error(
72910
+ `${args.referenceLabel} references value "${value.id}" owned by "${String(value.containerId)}", expected "${args.ownerId}".`
72911
+ );
72912
+ }
72913
+ }
72224
72914
  function assertConcreteWorldClass(args) {
72225
72915
  const schemaClass2 = args.classesById.get(args.classId);
72226
72916
  if (schemaClass2 === void 0) {
@@ -72238,6 +72928,58 @@ function assertConcreteWorldClass(args) {
72238
72928
  throw new Error(`${args.label} must reference a concrete class.`);
72239
72929
  }
72240
72930
  }
72931
+ function effectiveTargetIds(args) {
72932
+ return new Set(
72933
+ resolveEffectiveClassRelations(args).map(
72934
+ (relation) => relation.targetRecordId
72935
+ )
72936
+ );
72937
+ }
72938
+ function worldKindForValue(value, classes) {
72939
+ return typeof value.classId === "string" ? resolveWorldSystemClassKind(value.classId, classes) : null;
72940
+ }
72941
+ function requiredValueClassId(value, label) {
72942
+ if (typeof value.classId === "string" && value.classId.length > 0) {
72943
+ return value.classId;
72944
+ }
72945
+ throw new Error(`${label} value "${value.id}" is missing classId.`);
72946
+ }
72947
+ function valueObjectRecord(value) {
72948
+ if (value.value === null || typeof value.value !== "object") return null;
72949
+ if (Array.isArray(value.value)) return null;
72950
+ return value.value;
72951
+ }
72952
+ function referencedValue(reference2, valuesById, label) {
72953
+ if (reference2 === void 0 || reference2 === null) return null;
72954
+ if (typeof reference2 !== "string" || reference2.length === 0) {
72955
+ throw new Error(`${label} must reference a value id.`);
72956
+ }
72957
+ const value = valuesById.get(reference2);
72958
+ if (value === void 0) {
72959
+ throw new Error(`${label} references missing value "${reference2}".`);
72960
+ }
72961
+ return value;
72962
+ }
72963
+ function containmentEntryIds(listValue2, containedIds) {
72964
+ const ids = /* @__PURE__ */ new Set();
72965
+ if (Array.isArray(listValue2.value)) {
72966
+ for (const valueId of listValue2.value) {
72967
+ if (typeof valueId === "string" && valueId.length > 0) ids.add(valueId);
72968
+ }
72969
+ }
72970
+ for (const valueId of containedIds.get(listValue2.id) ?? []) ids.add(valueId);
72971
+ return [...ids];
72972
+ }
72973
+ function containedValueIdsByContainer(values) {
72974
+ const result = /* @__PURE__ */ new Map();
72975
+ for (const value of values) {
72976
+ if (typeof value.containerId !== "string") continue;
72977
+ const ids = result.get(value.containerId) ?? [];
72978
+ ids.push(value.id);
72979
+ result.set(value.containerId, ids);
72980
+ }
72981
+ return result;
72982
+ }
72241
72983
  function optionalNonEmptyString(value) {
72242
72984
  return typeof value === "string" && value.length > 0 ? value : null;
72243
72985
  }
@@ -80949,6 +81691,16 @@ function assertProjectVersionWholeGraphWritesValid(args) {
80949
81691
  assertStagedUnitySingletonValid(projected, args.changes);
80950
81692
  assertStagedProjectInterfaceValid(projected, args.changes);
80951
81693
  assertStagedTileGridReferencesValid(args.document, projected, args.changes);
81694
+ assertStagedInternalRecordRelationsValid(
81695
+ args.document,
81696
+ projected,
81697
+ args.changes
81698
+ );
81699
+ assertStagedWorldContentLayerBindingsValid(
81700
+ args.document,
81701
+ projected,
81702
+ args.changes
81703
+ );
80952
81704
  assertAnimationClipDocumentValid(
80953
81705
  materializeDeclarationInitializersForAnimationValidation(projected)
80954
81706
  );
@@ -81137,6 +81889,188 @@ function containsDirectValueId(value, ids) {
81137
81889
  (entry) => typeof entry === "string" && ids.has(entry)
81138
81890
  );
81139
81891
  }
81892
+ function assertStagedInternalRecordRelationsValid(current, projected, changes) {
81893
+ if (!stagedChangesAffectClassRelations(current, changes)) return;
81894
+ validateInternalRecordRelations({
81895
+ relations: projected.internalRecordRelations ?? [],
81896
+ endpoints: collectProjectDocumentRelationEndpoints(projected),
81897
+ classes: projected.classes
81898
+ });
81899
+ }
81900
+ function stagedChangesAffectClassRelations(current, changes) {
81901
+ const classesById = new Map(
81902
+ current.classes.map((schemaClass2) => [schemaClass2.id, schemaClass2])
81903
+ );
81904
+ const valuesById = new Map(current.values.map((value) => [value.id, value]));
81905
+ for (const change of changes) {
81906
+ if (change.recordKind === "internal-record-relation") return true;
81907
+ if (change.recordKind === "class") {
81908
+ if (change.operation !== "update") return true;
81909
+ if (change.deleted === true) return true;
81910
+ const before2 = classesById.get(change.recordId);
81911
+ if (before2 === void 0) return true;
81912
+ const after = change.nextData;
81913
+ if (!isPlainRecord4(after)) return true;
81914
+ if (before2.extendsClassId !== after.extendsClassId) return true;
81915
+ continue;
81916
+ }
81917
+ if (change.recordKind !== "value") continue;
81918
+ const before = valuesById.get(change.recordId);
81919
+ if (relationEndpointClassId(before) !== relationEndpointClassId(change.nextData)) {
81920
+ return true;
81921
+ }
81922
+ }
81923
+ return false;
81924
+ }
81925
+ function assertStagedWorldContentLayerBindingsValid(current, projected, changes) {
81926
+ if (!stagedChangesRequireWorldLayerBindingValidation(current, changes)) {
81927
+ return;
81928
+ }
81929
+ const classes = projected.classes;
81930
+ const relations = projected.internalRecordRelations ?? [];
81931
+ validateWorldContentSidecars({
81932
+ classes,
81933
+ relations,
81934
+ values: projected.values
81935
+ });
81936
+ validateWorldLayerLinkClassTargets({
81937
+ classes,
81938
+ relations,
81939
+ classIds: stagedAffectedWorldLayerLinkClassIds({
81940
+ classes,
81941
+ relations,
81942
+ current,
81943
+ changes
81944
+ })
81945
+ });
81946
+ }
81947
+ function stagedChangesRequireWorldLayerBindingValidation(current, changes) {
81948
+ const classesById = new Map(
81949
+ current.classes.map((schemaClass2) => [schemaClass2.id, schemaClass2])
81950
+ );
81951
+ const valuesById = new Map(current.values.map((value) => [value.id, value]));
81952
+ const valueChanges = [];
81953
+ for (const change of changes) {
81954
+ if (change.recordKind === "internal-record-relation") return true;
81955
+ if (change.recordKind === "value") {
81956
+ valueChanges.push(change);
81957
+ continue;
81958
+ }
81959
+ if (change.recordKind !== "class") continue;
81960
+ if (change.operation !== "update") return true;
81961
+ if (change.deleted === true) return true;
81962
+ const before = classesById.get(change.recordId);
81963
+ if (before === void 0) return true;
81964
+ const after = change.nextData;
81965
+ if (!isPlainRecord4(after)) return true;
81966
+ if (before.extendsClassId !== after.extendsClassId) return true;
81967
+ if (before.isAbstract !== after.isAbstract) return true;
81968
+ if (!worldClassSystemBlockIsEqual(before.system, after.system)) return true;
81969
+ }
81970
+ if (valueChanges.length === 0) return false;
81971
+ const graph = createWorldReferenceGraph({
81972
+ classes: current.classes,
81973
+ values: []
81974
+ });
81975
+ for (const change of valueChanges) {
81976
+ const before = valuesById.get(change.recordId);
81977
+ if (hasWorldLayerOverrideMetadata(before) || hasWorldLayerOverrideMetadata(change.nextData)) {
81978
+ return true;
81979
+ }
81980
+ const classIds = [
81981
+ relationEndpointClassId(before),
81982
+ relationEndpointClassId(change.nextData)
81983
+ ].filter((classId) => classId !== void 0);
81984
+ for (const classId of classIds) {
81985
+ const worldKind = resolveWorldKindFromClassMap(
81986
+ classId,
81987
+ graph.classesById
81988
+ );
81989
+ if (worldKind === NeoWorldSystemClassKind.TileLayerLink) return true;
81990
+ if (worldKind === NeoWorldSystemClassKind.ObjectLayerLink) return true;
81991
+ }
81992
+ }
81993
+ return false;
81994
+ }
81995
+ function stagedAffectedWorldLayerLinkClassIds(args) {
81996
+ const baseRelationsById = new Map(
81997
+ (args.current.internalRecordRelations ?? []).map((relation) => [
81998
+ relation.id,
81999
+ relation
82000
+ ])
82001
+ );
82002
+ const roots = /* @__PURE__ */ new Set();
82003
+ const changedClassIds = /* @__PURE__ */ new Set();
82004
+ for (const change of args.changes) {
82005
+ if (change.recordKind === "class") {
82006
+ changedClassIds.add(change.recordId);
82007
+ roots.add(change.recordId);
82008
+ continue;
82009
+ }
82010
+ if (change.recordKind !== "internal-record-relation") continue;
82011
+ const candidates = [
82012
+ baseRelationsById.get(change.recordId),
82013
+ change.nextData
82014
+ ];
82015
+ for (const candidate of candidates) {
82016
+ if (!isPlainRecord4(candidate)) continue;
82017
+ const relationKind = candidate.relationKind;
82018
+ if (typeof relationKind !== "string") continue;
82019
+ if (!isStagedWorldLayerLinkTargetRelationKind(relationKind)) continue;
82020
+ const sourceRecordId = candidate.sourceRecordId;
82021
+ if (typeof sourceRecordId !== "string") continue;
82022
+ roots.add(sourceRecordId);
82023
+ }
82024
+ }
82025
+ for (const relation of args.relations) {
82026
+ if (!isStagedWorldLayerLinkTargetRelationKind(relation.relationKind)) {
82027
+ continue;
82028
+ }
82029
+ if (!changedClassIds.has(relation.targetRecordId)) continue;
82030
+ roots.add(relation.sourceRecordId);
82031
+ }
82032
+ const affected = new Set(roots);
82033
+ let added = true;
82034
+ while (added) {
82035
+ added = false;
82036
+ for (const schemaClass2 of args.classes) {
82037
+ if (schemaClass2.extendsClassId === void 0) continue;
82038
+ if (!affected.has(schemaClass2.extendsClassId)) continue;
82039
+ if (affected.has(schemaClass2.id)) continue;
82040
+ affected.add(schemaClass2.id);
82041
+ added = true;
82042
+ }
82043
+ }
82044
+ return affected;
82045
+ }
82046
+ function isStagedWorldLayerLinkTargetRelationKind(relationKind) {
82047
+ if (relationKind === InternalRecordRelationKind.WorldTileLayerLinkTarget) {
82048
+ return true;
82049
+ }
82050
+ return relationKind === InternalRecordRelationKind.WorldObjectLayerLinkTarget;
82051
+ }
82052
+ function worldClassSystemBlockIsEqual(before, after) {
82053
+ return projectRecordDataIsSemanticallyEqual(
82054
+ { system: before },
82055
+ { system: after }
82056
+ );
82057
+ }
82058
+ function hasWorldLayerOverrideMetadata(record3) {
82059
+ if (!isPlainRecord4(record3)) return false;
82060
+ const value = record3.value;
82061
+ if (!isPlainRecord4(value)) return false;
82062
+ return typeof value.layerOverrideValueId === "string";
82063
+ }
82064
+ function relationEndpointClassId(record3) {
82065
+ if (!isPlainRecord4(record3)) return void 0;
82066
+ if (typeof record3.classId === "string") return record3.classId;
82067
+ if (typeof record3.typeId === "string") return record3.typeId;
82068
+ return void 0;
82069
+ }
82070
+ function isPlainRecord4(value) {
82071
+ if (value === null || typeof value !== "object") return false;
82072
+ return !Array.isArray(value);
82073
+ }
81140
82074
  function assertStagedProjectInterfaceValid(projected, changes) {
81141
82075
  const relevant = changes.filter(
81142
82076
  (change) => INTERFACE_VALIDATED_RECORD_KINDS.has(change.recordKind)
@@ -81254,6 +82188,10 @@ var INTERFACE_VALIDATED_RECORD_KINDS;
81254
82188
  var init_project_version_whole_graph_validation = __esm({
81255
82189
  "../src/database/project-version-whole-graph-validation.ts"() {
81256
82190
  "use strict";
82191
+ init_internal_record_relations();
82192
+ init_world_content_sidecar_validation();
82193
+ init_world_layer_link_target();
82194
+ init_core();
81257
82195
  init_animation_clips();
81258
82196
  init_projectInterfaceValidation();
81259
82197
  init_project_schema_identifier_validation();
@@ -81264,6 +82202,7 @@ var init_project_version_whole_graph_validation = __esm({
81264
82202
  init_init_backed_value_materialization();
81265
82203
  init_world_system_classes();
81266
82204
  init_project_world_reference_graph();
82205
+ init_project_record_semantics();
81267
82206
  INTERFACE_VALIDATED_RECORD_KINDS = /* @__PURE__ */ new Set(["member", "class", "constructor", "interface"]);
81268
82207
  }
81269
82208
  });
@@ -81556,6 +82495,7 @@ function replayStoredConstructionV4(args) {
81556
82495
  );
81557
82496
  }
81558
82497
  if (args.evaluate === false) return /* @__PURE__ */ new Map();
82498
+ compilePulledUncompiledConstructorsV4(document, compilationProject);
81559
82499
  assertPulledConstructorsCompiled(document);
81560
82500
  const compiledDependencies = /* @__PURE__ */ new Set();
81561
82501
  let materialized;
@@ -81598,6 +82538,34 @@ function replayStoredConstructionV4(args) {
81598
82538
  ])
81599
82539
  );
81600
82540
  }
82541
+ function compilePulledUncompiledConstructorsV4(document, compilationProject) {
82542
+ const uncompiled = (document.constructors ?? []).filter(
82543
+ (constructor2) => !isNeoClassConstructor(constructor2)
82544
+ );
82545
+ if (uncompiled.length === 0) return;
82546
+ const project = compilationProject ?? createNeoScriptCompilationProject({
82547
+ project: document.project,
82548
+ projectFiles: document.projectFiles,
82549
+ members: document.members,
82550
+ classes: document.classes,
82551
+ enums: document.enums,
82552
+ interfaces: document.interfaces,
82553
+ constructors: document.constructors ?? []
82554
+ });
82555
+ const compileArgs = {
82556
+ project: document.project,
82557
+ projectFiles: document.projectFiles,
82558
+ members: document.members,
82559
+ classes: document.classes,
82560
+ enums: document.enums,
82561
+ interfaces: document.interfaces,
82562
+ constructors: document.constructors ?? [],
82563
+ compilationProject: project
82564
+ };
82565
+ for (const constructor2 of uncompiled) {
82566
+ compileConstructorRecord({ ...compileArgs, constructor: constructor2 });
82567
+ }
82568
+ }
81601
82569
  function valueInitializerCompilationSites(document) {
81602
82570
  const cached = pulledValueInitializerCompilationSites.get(document);
81603
82571
  if (cached !== void 0) return cached;
@@ -81713,13 +82681,55 @@ function compilePulledMemberInitializerBodyV4(document, memberId, compilationPro
81713
82681
  });
81714
82682
  }
81715
82683
  function readPulledProjectDocumentV4(records2) {
81716
- return readProjectDocument(
81717
- // Replay compilation mutates authored `init` envelopes with transient IR.
81718
- // Keep that evaluator-local: the input records are also the source commit
81719
- // payload, where compiled bodies are deliberately absent.
81720
- structuredClone(pulledProjectDocumentRaw(replayWorkspace(records2))),
81721
- { constructors: "authored-or-compiled" }
82684
+ const raw = structuredClone(
82685
+ pulledProjectDocumentRaw(replayWorkspace(records2))
82686
+ );
82687
+ return readProjectDocument(completeProspectiveLocalizedTexts(raw), {
82688
+ constructors: "authored-or-compiled",
82689
+ identities: "prospective"
82690
+ });
82691
+ }
82692
+ function completeProspectiveLocalizedTexts(raw) {
82693
+ const localizedTexts = raw.localizedTexts;
82694
+ if (!Array.isArray(localizedTexts)) return raw;
82695
+ const incomplete = localizedTexts.find((text) => !isLocalizedText(text));
82696
+ if (incomplete === void 0) return raw;
82697
+ const config = localizedTextEnvelopeConfig(
82698
+ raw.localizationConfig,
82699
+ prospectiveLocalizedTextId(incomplete)
81722
82700
  );
82701
+ return {
82702
+ ...raw,
82703
+ localizedTexts: localizedTexts.map(
82704
+ (text) => isLocalizedText(text) ? text : completeLocalizedTextCreateEnvelope(text, config)
82705
+ )
82706
+ };
82707
+ }
82708
+ function localizedTextEnvelopeConfig(value, textId) {
82709
+ if (!isObjectRecord2(value)) {
82710
+ throw new Error(
82711
+ `Localized text "${textId}" needs the server create envelope, but the project carries no localization config record to mint it from.`
82712
+ );
82713
+ }
82714
+ if (typeof value.mainLocale !== "string") {
82715
+ throw new Error(
82716
+ `Localized text "${textId}" needs the server create envelope, but the project localization config declares no main locale.`
82717
+ );
82718
+ }
82719
+ if (typeof value.mainLocaleDefaultStatusId !== "string") {
82720
+ throw new Error(
82721
+ `Localized text "${textId}" needs the server create envelope, but the project localization config declares no main-locale default status.`
82722
+ );
82723
+ }
82724
+ return {
82725
+ mainLocale: value.mainLocale,
82726
+ mainLocaleDefaultStatusId: value.mainLocaleDefaultStatusId
82727
+ };
82728
+ }
82729
+ function prospectiveLocalizedTextId(value) {
82730
+ if (!isObjectRecord2(value)) return "<non-object>";
82731
+ if (typeof value.id !== "string") return "<unidentified>";
82732
+ return value.id;
81723
82733
  }
81724
82734
  function replayWorkspace(records2) {
81725
82735
  const stateRecords = {};
@@ -81758,6 +82768,7 @@ var init_initializer_replay = __esm({
81758
82768
  init_value_row_owner_members();
81759
82769
  init_inheritance();
81760
82770
  init_project_document_read();
82771
+ init_localization2();
81761
82772
  init_server_preparation_preflight();
81762
82773
  init_projection();
81763
82774
  init_constructors2();
@@ -82842,6 +83853,13 @@ function constructorArgumentValueSlices(authoredSlice) {
82842
83853
  );
82843
83854
  });
82844
83855
  }
83856
+ function unattachedAuthoredRowId(authoredSlice) {
83857
+ if (authoredSlice === void 0) return null;
83858
+ const match = LEADING_AUTHORED_ROW_ID.exec(
83859
+ normalizeInitializerSource(authoredSlice)
83860
+ );
83861
+ return match?.[1] ?? null;
83862
+ }
82845
83863
  function initializerExpressionSlice(authoredSlice) {
82846
83864
  if (authoredSlice === void 0) return void 0;
82847
83865
  let text = normalizeInitializerSource(authoredSlice);
@@ -83212,6 +84230,12 @@ function lowerSeedRow(context, member, sourceExpression, source, valueId, path,
83212
84230
  memberClassName(context, resolvedMember),
83213
84231
  bindingRuntimeIdentifiers(context, source)
83214
84232
  )) {
84233
+ const unattachedId = annotated.id === null ? unattachedAuthoredRowId(authoredSlice) : null;
84234
+ if (unattachedId !== null) {
84235
+ throw new Error(
84236
+ `Value ${path} in ${source.label} writes @id(${JSON.stringify(unattachedId)}) on part of a computed expression rather than on the row. Parenthesize the expression so the annotation names the whole row.`
84237
+ );
84238
+ }
83215
84239
  if (annotated.id === null && isPendingId(valueId) && !context.pendingValueIdentitySites.has(valueId)) {
83216
84240
  context.pendingValueIdentitySites.set(valueId, {
83217
84241
  id: valueId,
@@ -87233,7 +88257,7 @@ function memberDefaultBody(member) {
87233
88257
  if (!("value" in defaultValue)) return null;
87234
88258
  return defaultValue.value;
87235
88259
  }
87236
- var INFERRED_GENERIC_CLASS_PREFIX, MEMBER_KIND_DICTIONARY, MEMBER_KIND_LIST, MEMBER_KIND_CLASS, CANONICAL_CONSTRUCTOR_INLINE_WIDTH;
88260
+ var INFERRED_GENERIC_CLASS_PREFIX, MEMBER_KIND_DICTIONARY, MEMBER_KIND_LIST, MEMBER_KIND_CLASS, LEADING_AUTHORED_ROW_ID, CANONICAL_CONSTRUCTOR_INLINE_WIDTH;
87237
88261
  var init_value_sources = __esm({
87238
88262
  "src/project-source/value-sources.ts"() {
87239
88263
  "use strict";
@@ -87260,6 +88284,7 @@ var init_value_sources = __esm({
87260
88284
  MEMBER_KIND_DICTIONARY = 5;
87261
88285
  MEMBER_KIND_LIST = 6;
87262
88286
  MEMBER_KIND_CLASS = 7;
88287
+ LEADING_AUTHORED_ROW_ID = /^@id\(\s*"((?:[^"\\]|\\.)*)"\s*\)/;
87263
88288
  CANONICAL_CONSTRUCTOR_INLINE_WIDTH = 88;
87264
88289
  }
87265
88290
  });