@neocompose/cli 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/neo.mjs CHANGED
@@ -1386,11 +1386,11 @@ var init_source_protocol = __esm({
1386
1386
  "src/schema/generated/source-protocol.ts"() {
1387
1387
  "use strict";
1388
1388
  SCHEMA_MANIFEST_FORMAT_VERSION = 3;
1389
- SCHEMA_MANIFEST_CONTRACT_VERSION = "3.0";
1389
+ SCHEMA_MANIFEST_CONTRACT_VERSION = "3.1";
1390
1390
  SCHEMA_SOURCE_MANIFEST_NAME = "neo-schema-manifest-v3";
1391
- SCHEMA_COMPILER_PROTOCOL_VERSION = 4;
1392
- SCHEMA_SDK_VERSION = "3.0.0";
1393
- SCHEMA_CLI_VERSION = "0.3.1";
1391
+ SCHEMA_COMPILER_PROTOCOL_VERSION = 5;
1392
+ SCHEMA_SDK_VERSION = "3.1.0";
1393
+ SCHEMA_CLI_VERSION = "0.4.0";
1394
1394
  SCHEMA_API_TARGET = "netstandard2.1";
1395
1395
  SCHEMA_REFERENCE_ASSEMBLY_SET = "NETStandard.Library.Ref/2.1.0";
1396
1396
  SCHEMA_REQUIRED_TOOLING_FILES = [
@@ -1455,7 +1455,7 @@ var init_source_protocol = __esm({
1455
1455
  "CompilerResponse": {
1456
1456
  "fields": {
1457
1457
  "protocolVersion": {
1458
- "literal": 4
1458
+ "literal": 5
1459
1459
  },
1460
1460
  "id": {
1461
1461
  "type": "string",
@@ -1560,7 +1560,8 @@ var init_source_protocol = __esm({
1560
1560
  "audioTemplate",
1561
1561
  "localization",
1562
1562
  "localizationStatus",
1563
- "registry"
1563
+ "registry",
1564
+ "relationConfiguration"
1564
1565
  ]
1565
1566
  },
1566
1567
  "id": {
@@ -9981,7 +9982,7 @@ var init_schema_contract_generated = __esm({
9981
9982
  "../packages/neoscript-language/src/schema-contract.generated.ts"() {
9982
9983
  "use strict";
9983
9984
  SCHEMA_MANIFEST_FORMAT_VERSION2 = 3;
9984
- SCHEMA_MANIFEST_CONTRACT_VERSION2 = "3.0";
9985
+ SCHEMA_MANIFEST_CONTRACT_VERSION2 = "3.1";
9985
9986
  }
9986
9987
  });
9987
9988
 
@@ -12106,7 +12107,8 @@ function assertSchemaManifestV3(value) {
12106
12107
  "textureTemplates",
12107
12108
  "audioTemplates",
12108
12109
  "localization",
12109
- "localizationStatuses"
12110
+ "localizationStatuses",
12111
+ "internalRecordRelations"
12110
12112
  ]);
12111
12113
  exactValue(
12112
12114
  manifest.formatVersion,
@@ -12135,6 +12137,11 @@ function assertSchemaManifestV3(value) {
12135
12137
  "$.localizationStatuses",
12136
12138
  assertLocalizationStatus
12137
12139
  );
12140
+ arrayOf(
12141
+ manifest.internalRecordRelations,
12142
+ "$.internalRecordRelations",
12143
+ assertInternalRecordRelation
12144
+ );
12138
12145
  uniqueIds(manifest.classes, "$.classes");
12139
12146
  uniqueIds(manifest.members, "$.members");
12140
12147
  uniqueIds(manifest.interfaces, "$.interfaces");
@@ -12142,8 +12149,283 @@ function assertSchemaManifestV3(value) {
12142
12149
  uniqueIds(manifest.textureTemplates, "$.textureTemplates");
12143
12150
  uniqueIds(manifest.audioTemplates, "$.audioTemplates");
12144
12151
  uniqueIds(manifest.localizationStatuses, "$.localizationStatuses");
12152
+ uniqueIds(manifest.internalRecordRelations, "$.internalRecordRelations");
12153
+ assertInternalRecordRelationInvariants(manifest);
12145
12154
  assertStaticMemberInvariants(manifest);
12146
12155
  }
12156
+ function assertInternalRecordRelation(value, path) {
12157
+ const relation = objectAt(value, path, [
12158
+ "id",
12159
+ "source",
12160
+ "relationKind",
12161
+ "sourceRecordKind",
12162
+ "sourceRecordId",
12163
+ "targetRecordKind",
12164
+ "targetRecordId",
12165
+ "order"
12166
+ ]);
12167
+ nonEmptyString(relation.id, `${path}.id`);
12168
+ assertSourceIdentity(relation.source, `${path}.source`);
12169
+ nonEmptyString(relation.relationKind, `${path}.relationKind`);
12170
+ projectRecordKind(relation.sourceRecordKind, `${path}.sourceRecordKind`);
12171
+ nonEmptyString(relation.sourceRecordId, `${path}.sourceRecordId`);
12172
+ projectRecordKind(relation.targetRecordKind, `${path}.targetRecordKind`);
12173
+ nonEmptyString(relation.targetRecordId, `${path}.targetRecordId`);
12174
+ if (relation.order !== null && (typeof relation.order !== "number" || !Number.isInteger(relation.order) || relation.order < 0)) {
12175
+ invalid(`${path}.order`, "expected null or a non-negative integer.");
12176
+ }
12177
+ }
12178
+ function assertInternalRecordRelationInvariants(manifest) {
12179
+ const relations = requireArray(
12180
+ manifest.internalRecordRelations,
12181
+ "$.internalRecordRelations"
12182
+ ).map(
12183
+ (value, index) => requireRecord(value, `$.internalRecordRelations[${index}]`)
12184
+ );
12185
+ const seenEdges = /* @__PURE__ */ new Map();
12186
+ const orderedGroups = /* @__PURE__ */ new Map();
12187
+ const classes = requireArray(manifest.classes, "$.classes").map(
12188
+ (value, index) => requireRecord(value, `$.classes[${index}]`)
12189
+ );
12190
+ const classesById = new Map(
12191
+ classes.map((schemaClass2) => [String(schemaClass2.id), schemaClass2])
12192
+ );
12193
+ const endpoints = manifestEndpointKeys(manifest, relations);
12194
+ const singletonSources = /* @__PURE__ */ new Map();
12195
+ const graph = /* @__PURE__ */ new Map();
12196
+ for (const [index, relation] of relations.entries()) {
12197
+ const path = `$.internalRecordRelations[${index}]`;
12198
+ const edgeKey = [
12199
+ relation.relationKind,
12200
+ relation.sourceRecordKind,
12201
+ relation.sourceRecordId,
12202
+ relation.targetRecordKind,
12203
+ relation.targetRecordId
12204
+ ].join("\0");
12205
+ const duplicate = seenEdges.get(edgeKey);
12206
+ if (duplicate !== void 0) {
12207
+ invalid(
12208
+ path,
12209
+ `duplicates the qualified edge declared at $.internalRecordRelations[${duplicate}].`
12210
+ );
12211
+ }
12212
+ seenEdges.set(edgeKey, index);
12213
+ const sourceKey = `${String(relation.sourceRecordKind)}:${String(relation.sourceRecordId)}`;
12214
+ const targetKey = `${String(relation.targetRecordKind)}:${String(relation.targetRecordId)}`;
12215
+ if (manifestContainsEndpointKind(String(relation.sourceRecordKind)) && !endpoints.has(sourceKey)) {
12216
+ invalid(
12217
+ `${path}.sourceRecordId`,
12218
+ `references missing ${String(relation.sourceRecordKind)} record ${JSON.stringify(relation.sourceRecordId)}.`
12219
+ );
12220
+ }
12221
+ if (manifestContainsEndpointKind(String(relation.targetRecordKind)) && !endpoints.has(targetKey)) {
12222
+ invalid(
12223
+ `${path}.targetRecordId`,
12224
+ `references missing ${String(relation.targetRecordKind)} record ${JSON.stringify(relation.targetRecordId)}.`
12225
+ );
12226
+ }
12227
+ if (sourceKey === targetKey) {
12228
+ invalid(
12229
+ path,
12230
+ "self-edges are not allowed by the schema authoring contract."
12231
+ );
12232
+ }
12233
+ const targets = graph.get(sourceKey) ?? [];
12234
+ targets.push(targetKey);
12235
+ graph.set(sourceKey, targets);
12236
+ const contract = WORLD_RELATION_CONTRACTS[String(relation.relationKind)];
12237
+ if (contract === void 0) {
12238
+ invalid(
12239
+ `${path}.relationKind`,
12240
+ `uses unknown relation kind ${JSON.stringify(relation.relationKind)}.`
12241
+ );
12242
+ } else {
12243
+ if (relation.sourceRecordKind !== contract.sourceRecordKind || relation.targetRecordKind !== contract.targetRecordKind) {
12244
+ invalid(
12245
+ path,
12246
+ `${String(relation.relationKind)} requires ${contract.sourceRecordKind}-to-${contract.targetRecordKind} endpoints.`
12247
+ );
12248
+ }
12249
+ const sourceClass = contract.sourceRecordKind === "class" ? classesById.get(String(relation.sourceRecordId)) : void 0;
12250
+ const targetClass = contract.targetRecordKind === "class" ? classesById.get(String(relation.targetRecordId)) : void 0;
12251
+ if (sourceClass !== void 0) {
12252
+ const actual = effectiveWorldKind(sourceClass, classesById);
12253
+ if (actual !== contract.sourceWorldKind) {
12254
+ invalid(
12255
+ `${path}.sourceRecordId`,
12256
+ `${String(relation.relationKind)} requires a ${contract.sourceWorldKind} source Class; received ${actual ?? "no world kind"}.`
12257
+ );
12258
+ }
12259
+ }
12260
+ if (targetClass !== void 0) {
12261
+ const actual = effectiveWorldKind(targetClass, classesById);
12262
+ if (actual !== contract.targetWorldKind) {
12263
+ invalid(
12264
+ `${path}.targetRecordId`,
12265
+ `${String(relation.relationKind)} requires a ${contract.targetWorldKind} target Class; received ${actual ?? "no world kind"}.`
12266
+ );
12267
+ }
12268
+ if (!contract.abstractTarget && targetClass.declarationModifier === "abstract") {
12269
+ invalid(
12270
+ `${path}.targetRecordId`,
12271
+ `${String(relation.relationKind)} requires a concrete target Class.`
12272
+ );
12273
+ }
12274
+ }
12275
+ if (contract.ordered !== (relation.order !== null)) {
12276
+ invalid(
12277
+ `${path}.order`,
12278
+ contract.ordered ? `${String(relation.relationKind)} requires an ordered position.` : `${String(relation.relationKind)} is unordered and must use null.`
12279
+ );
12280
+ }
12281
+ if (contract.singleton) {
12282
+ const singletonKey = `${String(relation.relationKind)}\0${sourceKey}`;
12283
+ const duplicateSingleton = singletonSources.get(singletonKey);
12284
+ if (duplicateSingleton !== void 0) {
12285
+ invalid(
12286
+ path,
12287
+ `declares a second direct singleton already present at $.internalRecordRelations[${duplicateSingleton}].`
12288
+ );
12289
+ }
12290
+ singletonSources.set(singletonKey, index);
12291
+ }
12292
+ }
12293
+ if (relation.order === null) continue;
12294
+ const groupKey = [
12295
+ relation.relationKind,
12296
+ relation.sourceRecordKind,
12297
+ relation.sourceRecordId
12298
+ ].join("\0");
12299
+ const group = orderedGroups.get(groupKey) ?? [];
12300
+ group.push({ order: Number(relation.order), index });
12301
+ orderedGroups.set(groupKey, group);
12302
+ }
12303
+ for (const group of orderedGroups.values()) {
12304
+ group.sort((left, right) => left.order - right.order);
12305
+ for (const [expected, entry] of group.entries()) {
12306
+ if (entry.order === expected) continue;
12307
+ invalid(
12308
+ `$.internalRecordRelations[${entry.index}].order`,
12309
+ `ordered direct relation positions must be contiguous from zero; expected ${expected}.`
12310
+ );
12311
+ }
12312
+ }
12313
+ assertAcyclicRelationGraph(graph);
12314
+ assertDefaultLayerCompatibility(relations, classesById);
12315
+ }
12316
+ function effectiveWorldKind(schemaClass2, classesById) {
12317
+ const visited = /* @__PURE__ */ new Set();
12318
+ let current = schemaClass2;
12319
+ while (current !== void 0) {
12320
+ const id = String(current.id);
12321
+ if (visited.has(id)) return null;
12322
+ visited.add(id);
12323
+ const system = current.system;
12324
+ if (system !== null && typeof system === "object" && !Array.isArray(system)) {
12325
+ const worldKind2 = system.worldKind;
12326
+ if (typeof worldKind2 === "string") return worldKind2;
12327
+ }
12328
+ current = typeof current.extendsClassId === "string" ? classesById.get(current.extendsClassId) : void 0;
12329
+ }
12330
+ return null;
12331
+ }
12332
+ function manifestEndpointKeys(manifest, relations) {
12333
+ const result = /* @__PURE__ */ new Set();
12334
+ const collections = [
12335
+ ["classes", "class"],
12336
+ ["members", "member"],
12337
+ ["interfaces", "interface"],
12338
+ ["enums", "enum"],
12339
+ ["textureTemplates", "unity-texture-template"],
12340
+ ["audioTemplates", "unity-audio-clip-template"],
12341
+ ["localizationStatuses", "localization-status"]
12342
+ ];
12343
+ for (const [collection, kind] of collections) {
12344
+ for (const entry of requireArray(manifest[collection], `$.${collection}`)) {
12345
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry))
12346
+ continue;
12347
+ const id = entry.id;
12348
+ if (typeof id === "string") result.add(`${kind}:${id}`);
12349
+ }
12350
+ }
12351
+ const localization = requireRecord(manifest.localization, "$.localization");
12352
+ if (typeof localization.id === "string") {
12353
+ result.add(`localization-config:${localization.id}`);
12354
+ }
12355
+ for (const relation of relations) {
12356
+ result.add(`internal-record-relation:${String(relation.id)}`);
12357
+ }
12358
+ return result;
12359
+ }
12360
+ function manifestContainsEndpointKind(recordKind) {
12361
+ return MANIFEST_ENDPOINT_KINDS.has(recordKind);
12362
+ }
12363
+ function assertAcyclicRelationGraph(graph) {
12364
+ const complete2 = /* @__PURE__ */ new Set();
12365
+ const visiting = /* @__PURE__ */ new Set();
12366
+ const visit = (node) => {
12367
+ if (complete2.has(node)) return;
12368
+ if (visiting.has(node)) {
12369
+ invalid(
12370
+ "$.internalRecordRelations",
12371
+ `declared relations contain a cycle through ${JSON.stringify(node)}.`
12372
+ );
12373
+ }
12374
+ visiting.add(node);
12375
+ for (const target of graph.get(node) ?? []) visit(target);
12376
+ visiting.delete(node);
12377
+ complete2.add(node);
12378
+ };
12379
+ for (const node of graph.keys()) visit(node);
12380
+ }
12381
+ function assertDefaultLayerCompatibility(relations, classesById) {
12382
+ const pairs = [
12383
+ ["world.tile.default-layer", "world.tile.compatible-layer"],
12384
+ ["world.object.default-layer", "world.object.compatible-layer"]
12385
+ ];
12386
+ for (const [defaultKind, compatibleKind] of pairs) {
12387
+ for (const relation of relations.filter(
12388
+ (candidate) => candidate.relationKind === defaultKind
12389
+ )) {
12390
+ const sourceAncestors = classAncestorIds(
12391
+ String(relation.sourceRecordId),
12392
+ classesById
12393
+ );
12394
+ const targetAncestors = classAncestorIds(
12395
+ String(relation.targetRecordId),
12396
+ classesById
12397
+ );
12398
+ const covered = relations.some(
12399
+ (candidate) => candidate.relationKind === compatibleKind && sourceAncestors.includes(String(candidate.sourceRecordId)) && targetAncestors.includes(String(candidate.targetRecordId))
12400
+ );
12401
+ if (!covered) {
12402
+ invalid(
12403
+ "$.internalRecordRelations",
12404
+ `${defaultKind} relation ${JSON.stringify(relation.id)} must also be covered by ${compatibleKind}.`
12405
+ );
12406
+ }
12407
+ }
12408
+ }
12409
+ }
12410
+ function classAncestorIds(classId, classesById) {
12411
+ const result = [];
12412
+ const visited = /* @__PURE__ */ new Set();
12413
+ let current = classesById.get(classId);
12414
+ while (current !== void 0) {
12415
+ const id = String(current.id);
12416
+ if (visited.has(id)) break;
12417
+ visited.add(id);
12418
+ result.push(id);
12419
+ current = typeof current.extendsClassId === "string" ? classesById.get(current.extendsClassId) : void 0;
12420
+ }
12421
+ return result;
12422
+ }
12423
+ function projectRecordKind(value, path) {
12424
+ if (typeof value === "string" && PROJECT_RECORD_KINDS.has(value)) {
12425
+ return;
12426
+ }
12427
+ invalid(path, "expected a registered project record kind.");
12428
+ }
12147
12429
  function assertStaticMemberInvariants(manifest) {
12148
12430
  const members = requireArray(manifest.members, "$.members").map(
12149
12431
  (value, index) => requireRecord(value, `$.members[${index}]`)
@@ -13551,7 +13833,7 @@ function exactValue(value, expected, path) {
13551
13833
  function invalid(path, message) {
13552
13834
  throw new SchemaManifestValidationError(path, message);
13553
13835
  }
13554
- var SchemaManifestValidationError, SOURCE_KINDS, SYSTEM_OPERATIONS, WORLD_KINDS, MEMBER_COMMON_KEYS, MEMBER_KEYS_BY_KIND, PRIMITIVE_TYPE_KINDS, TEXTURE_TYPES, ALPHA_SOURCES, NPOT_SCALES, WRAP_MODES, RESIZE_ALGORITHMS, TEXTURE_COMPRESSIONS, PLATFORM_FORMATS, SPRITE_ALIGNMENTS;
13836
+ var SchemaManifestValidationError, WORLD_RELATION_CONTRACTS, MANIFEST_ENDPOINT_KINDS, PROJECT_RECORD_KINDS, SOURCE_KINDS, SYSTEM_OPERATIONS, WORLD_KINDS, MEMBER_COMMON_KEYS, MEMBER_KEYS_BY_KIND, PRIMITIVE_TYPE_KINDS, TEXTURE_TYPES, ALPHA_SOURCES, NPOT_SCALES, WRAP_MODES, RESIZE_ALGORITHMS, TEXTURE_COMPRESSIONS, PLATFORM_FORMATS, SPRITE_ALIGNMENTS;
13555
13837
  var init_validate = __esm({
13556
13838
  "src/schema/manifest/validate.ts"() {
13557
13839
  "use strict";
@@ -13566,6 +13848,138 @@ var init_validate = __esm({
13566
13848
  path;
13567
13849
  code;
13568
13850
  };
13851
+ WORLD_RELATION_CONTRACTS = {
13852
+ "world.grid.tile-import": {
13853
+ sourceRecordKind: "class",
13854
+ targetRecordKind: "class",
13855
+ sourceWorldKind: "tileGrid",
13856
+ targetWorldKind: "tile",
13857
+ abstractTarget: true,
13858
+ ordered: false,
13859
+ singleton: false
13860
+ },
13861
+ "world.grid.object-import": {
13862
+ sourceRecordKind: "class",
13863
+ targetRecordKind: "class",
13864
+ sourceWorldKind: "tileGrid",
13865
+ targetWorldKind: "object",
13866
+ abstractTarget: true,
13867
+ ordered: false,
13868
+ singleton: false
13869
+ },
13870
+ "world.grid.tile-layer": {
13871
+ sourceRecordKind: "class",
13872
+ targetRecordKind: "class",
13873
+ sourceWorldKind: "tileGrid",
13874
+ targetWorldKind: "tileLayer",
13875
+ abstractTarget: false,
13876
+ ordered: true,
13877
+ singleton: false
13878
+ },
13879
+ "world.grid.object-layer": {
13880
+ sourceRecordKind: "class",
13881
+ targetRecordKind: "class",
13882
+ sourceWorldKind: "tileGrid",
13883
+ targetWorldKind: "objectLayer",
13884
+ abstractTarget: false,
13885
+ ordered: true,
13886
+ singleton: false
13887
+ },
13888
+ "world.tile.compatible-layer": {
13889
+ sourceRecordKind: "class",
13890
+ targetRecordKind: "class",
13891
+ sourceWorldKind: "tile",
13892
+ targetWorldKind: "tileLayer",
13893
+ abstractTarget: true,
13894
+ ordered: false,
13895
+ singleton: false
13896
+ },
13897
+ "world.tile.default-layer": {
13898
+ sourceRecordKind: "class",
13899
+ targetRecordKind: "class",
13900
+ sourceWorldKind: "tile",
13901
+ targetWorldKind: "tileLayer",
13902
+ abstractTarget: false,
13903
+ ordered: false,
13904
+ singleton: true
13905
+ },
13906
+ "world.object.compatible-layer": {
13907
+ sourceRecordKind: "class",
13908
+ targetRecordKind: "class",
13909
+ sourceWorldKind: "object",
13910
+ targetWorldKind: "objectLayer",
13911
+ abstractTarget: true,
13912
+ ordered: false,
13913
+ singleton: false
13914
+ },
13915
+ "world.object.default-layer": {
13916
+ sourceRecordKind: "class",
13917
+ targetRecordKind: "class",
13918
+ sourceWorldKind: "object",
13919
+ targetWorldKind: "objectLayer",
13920
+ abstractTarget: false,
13921
+ ordered: false,
13922
+ singleton: true
13923
+ },
13924
+ "world.tile-layer-link.target": {
13925
+ sourceRecordKind: "class",
13926
+ targetRecordKind: "class",
13927
+ sourceWorldKind: "tileLayerLink",
13928
+ targetWorldKind: "tileLayer",
13929
+ abstractTarget: false,
13930
+ ordered: false,
13931
+ singleton: true
13932
+ },
13933
+ "world.object-layer-link.target": {
13934
+ sourceRecordKind: "class",
13935
+ targetRecordKind: "class",
13936
+ sourceWorldKind: "objectLayerLink",
13937
+ targetWorldKind: "objectLayer",
13938
+ abstractTarget: false,
13939
+ ordered: false,
13940
+ singleton: true
13941
+ },
13942
+ "world.smart-tile-neighbor.tile": {
13943
+ sourceRecordKind: "value",
13944
+ targetRecordKind: "class",
13945
+ sourceWorldKind: "smartTileNeighbor",
13946
+ targetWorldKind: "tile",
13947
+ abstractTarget: true,
13948
+ ordered: false,
13949
+ singleton: true
13950
+ }
13951
+ };
13952
+ MANIFEST_ENDPOINT_KINDS = /* @__PURE__ */ new Set([
13953
+ "class",
13954
+ "member",
13955
+ "interface",
13956
+ "enum",
13957
+ "unity-texture-template",
13958
+ "unity-audio-clip-template",
13959
+ "localization-config",
13960
+ "localization-status",
13961
+ "internal-record-relation"
13962
+ ]);
13963
+ PROJECT_RECORD_KINDS = /* @__PURE__ */ new Set([
13964
+ "project",
13965
+ "member",
13966
+ "value",
13967
+ "class",
13968
+ "internal-record-relation",
13969
+ "enum",
13970
+ "interface",
13971
+ "dialogue",
13972
+ "dialogue-node",
13973
+ "dialogue-group",
13974
+ "priority-group",
13975
+ "project-file",
13976
+ "unity-texture-template",
13977
+ "unity-audio-clip-template",
13978
+ "localization-config",
13979
+ "localization-status",
13980
+ "localized-text",
13981
+ "migration"
13982
+ ]);
13569
13983
  SOURCE_KINDS = /* @__PURE__ */ new Set([
13570
13984
  "class",
13571
13985
  "member",
@@ -13576,7 +13990,8 @@ var init_validate = __esm({
13576
13990
  "textureTemplate",
13577
13991
  "audioTemplate",
13578
13992
  "localization",
13579
- "localizationStatus"
13993
+ "localizationStatus",
13994
+ "internalRecordRelation"
13580
13995
  ]);
13581
13996
  SYSTEM_OPERATIONS = /* @__PURE__ */ new Set([
13582
13997
  "editRecord",
@@ -13585,7 +14000,6 @@ var init_validate = __esm({
13585
14000
  "replaceValue"
13586
14001
  ]);
13587
14002
  WORLD_KINDS = /* @__PURE__ */ new Set([
13588
- "worldAssets",
13589
14003
  "tileGrid",
13590
14004
  "tileLayer",
13591
14005
  "objectLayer",
@@ -14055,7 +14469,6 @@ function systemOperation(value, location2, frontend) {
14055
14469
  function worldKind(value, location2, frontend) {
14056
14470
  const result = lowerFirst(value);
14057
14471
  const allowed = /* @__PURE__ */ new Set([
14058
- "worldAssets",
14059
14472
  "tileGrid",
14060
14473
  "tileLayer",
14061
14474
  "objectLayer",
@@ -14085,7 +14498,7 @@ function worldKind(value, location2, frontend) {
14085
14498
  function lowerFirst(value) {
14086
14499
  return value.length === 0 ? value : `${value[0].toLowerCase()}${value.slice(1)}`;
14087
14500
  }
14088
- var SchemaFrontendError, SchemaFrontend, map, TEXTURE_TYPES2, ALPHA_SOURCES2, NPOT_SCALES2, MIP_FILTERS, WRAP_MODES2, FILTER_MODES, RESIZE_ALGORITHMS2, COMPRESSIONS, TEXTURE_FORMATS, SPRITE_MODES, MESH_TYPES, ALIGNMENTS, NORMAL_FILTERS, COOKIE_LIGHT_TYPES, SINGLE_CHANNELS, SWIZZLES, AUDIO_LOAD_TYPES, AUDIO_COMPRESSIONS, AUDIO_SAMPLE_RATES;
14501
+ var SchemaFrontendError, SPECIALIZED_RELATION_SETTINGS, PROJECT_RECORD_KIND_BY_ENUM, SchemaFrontend, map, TEXTURE_TYPES2, ALPHA_SOURCES2, NPOT_SCALES2, MIP_FILTERS, WRAP_MODES2, FILTER_MODES, RESIZE_ALGORITHMS2, COMPRESSIONS, TEXTURE_FORMATS, SPRITE_MODES, MESH_TYPES, ALIGNMENTS, NORMAL_FILTERS, COOKIE_LIGHT_TYPES, SINGLE_CHANNELS, SWIZZLES, AUDIO_LOAD_TYPES, AUDIO_COMPRESSIONS, AUDIO_SAMPLE_RATES;
14089
14502
  var init_frontend = __esm({
14090
14503
  "src/schema/frontend.ts"() {
14091
14504
  "use strict";
@@ -14101,6 +14514,98 @@ var init_frontend = __esm({
14101
14514
  }
14102
14515
  diagnostics;
14103
14516
  };
14517
+ SPECIALIZED_RELATION_SETTINGS = {
14518
+ "NeoCompose.Schema.NeoGridRelationSettings": [
14519
+ {
14520
+ property: "TileImports",
14521
+ relationKind: "world.grid.tile-import",
14522
+ collection: true,
14523
+ ordered: false
14524
+ },
14525
+ {
14526
+ property: "ObjectImports",
14527
+ relationKind: "world.grid.object-import",
14528
+ collection: true,
14529
+ ordered: false
14530
+ },
14531
+ {
14532
+ property: "TileLayers",
14533
+ relationKind: "world.grid.tile-layer",
14534
+ collection: true,
14535
+ ordered: true
14536
+ },
14537
+ {
14538
+ property: "ObjectLayers",
14539
+ relationKind: "world.grid.object-layer",
14540
+ collection: true,
14541
+ ordered: true
14542
+ }
14543
+ ],
14544
+ "NeoCompose.Schema.NeoTileRelationSettings": [
14545
+ {
14546
+ property: "CompatibleLayers",
14547
+ relationKind: "world.tile.compatible-layer",
14548
+ collection: true,
14549
+ ordered: false
14550
+ },
14551
+ {
14552
+ property: "DefaultLayer",
14553
+ relationKind: "world.tile.default-layer",
14554
+ collection: false,
14555
+ ordered: false
14556
+ }
14557
+ ],
14558
+ "NeoCompose.Schema.NeoObjectRelationSettings": [
14559
+ {
14560
+ property: "CompatibleLayers",
14561
+ relationKind: "world.object.compatible-layer",
14562
+ collection: true,
14563
+ ordered: false
14564
+ },
14565
+ {
14566
+ property: "DefaultLayer",
14567
+ relationKind: "world.object.default-layer",
14568
+ collection: false,
14569
+ ordered: false
14570
+ }
14571
+ ],
14572
+ "NeoCompose.Schema.NeoTileLayerLinkRelationSettings": [
14573
+ {
14574
+ property: "TargetLayer",
14575
+ relationKind: "world.tile-layer-link.target",
14576
+ collection: false,
14577
+ ordered: false
14578
+ }
14579
+ ],
14580
+ "NeoCompose.Schema.NeoObjectLayerLinkRelationSettings": [
14581
+ {
14582
+ property: "TargetLayer",
14583
+ relationKind: "world.object-layer-link.target",
14584
+ collection: false,
14585
+ ordered: false
14586
+ }
14587
+ ]
14588
+ };
14589
+ PROJECT_RECORD_KIND_BY_ENUM = {
14590
+ Project: "project",
14591
+ Member: "member",
14592
+ Value: "value",
14593
+ Class: "class",
14594
+ InternalRecordRelation: "internal-record-relation",
14595
+ Enum: "enum",
14596
+ Interface: "interface",
14597
+ Dialogue: "dialogue",
14598
+ DialogueNode: "dialogue-node",
14599
+ DialogueGroup: "dialogue-group",
14600
+ PriorityGroup: "priority-group",
14601
+ ProjectFile: "project-file",
14602
+ UnityTextureTemplate: "unity-texture-template",
14603
+ UnityAudioClipTemplate: "unity-audio-clip-template",
14604
+ LocalizationConfig: "localization-config",
14605
+ LocalizationStatus: "localization-status",
14606
+ LocalizedText: "localized-text",
14607
+ Migration: "migration"
14608
+ };
14104
14609
  SchemaFrontend = class {
14105
14610
  constructor(source, options) {
14106
14611
  this.source = source;
@@ -14167,6 +14672,7 @@ var init_frontend = __esm({
14167
14672
  }
14168
14673
  const localization = this.parseLocalization(localizationDeclarations[0]);
14169
14674
  const localizationStatuses = this.declarations.filter((entry) => entry.declaration.kind === "localizationStatus").map((entry) => this.parseLocalizationStatus(entry));
14675
+ const internalRecordRelations = this.parseInternalRecordRelations();
14170
14676
  const manifest = {
14171
14677
  formatVersion: SCHEMA_MANIFEST_FORMAT_VERSION,
14172
14678
  contractVersion: SCHEMA_MANIFEST_CONTRACT_VERSION,
@@ -14178,7 +14684,8 @@ var init_frontend = __esm({
14178
14684
  textureTemplates,
14179
14685
  audioTemplates,
14180
14686
  localization,
14181
- localizationStatuses
14687
+ localizationStatuses,
14688
+ internalRecordRelations
14182
14689
  };
14183
14690
  try {
14184
14691
  assertSchemaManifestV3(manifest);
@@ -14520,6 +15027,280 @@ var init_frontend = __esm({
14520
15027
  extendsGenericBindings
14521
15028
  };
14522
15029
  }
15030
+ parseInternalRecordRelations() {
15031
+ const result = [];
15032
+ for (const info of this.declarations.filter(
15033
+ (entry) => entry.declaration.kind === "class"
15034
+ )) {
15035
+ const fields = info.declaration.members.filter(
15036
+ (member) => member.kind === "settings" && member.name === "NeoRelations"
15037
+ );
15038
+ if (fields.length === 0) continue;
15039
+ if (fields.length !== 1) {
15040
+ this.fail(
15041
+ "NEO3120",
15042
+ `Class ${info.declaration.name} must declare at most one NeoRelations settings field.`,
15043
+ fields[1]?.location ?? info.declaration.location
15044
+ );
15045
+ }
15046
+ const field = fields[0];
15047
+ if (!field.modifiers.includes("static")) {
15048
+ this.fail(
15049
+ "NEO3121",
15050
+ `${info.declaration.name}.NeoRelations must be static.`,
15051
+ field.location
15052
+ );
15053
+ }
15054
+ if (field.initializer === void 0) {
15055
+ this.fail(
15056
+ "NEO3122",
15057
+ `${info.declaration.name}.NeoRelations requires an initializer.`,
15058
+ field.location
15059
+ );
15060
+ }
15061
+ const type = parseTypeShape(field.type ?? "").name;
15062
+ const settings = this.objectValue(
15063
+ field.initializer,
15064
+ `${info.declaration.name}.NeoRelations`,
15065
+ field.location
15066
+ );
15067
+ const groups = SPECIALIZED_RELATION_SETTINGS[type];
15068
+ if (groups === void 0) {
15069
+ this.fail(
15070
+ "NEO3123",
15071
+ `${info.declaration.name}.NeoRelations has unsupported type ${JSON.stringify(field.type)}.`,
15072
+ field.location
15073
+ );
15074
+ }
15075
+ for (const group of groups) {
15076
+ const raw = settings.properties?.[group.property];
15077
+ if (group.collection) {
15078
+ const entries = raw === void 0 ? [] : this.arrayValue(
15079
+ raw,
15080
+ `${type}.${group.property}`,
15081
+ field.location
15082
+ );
15083
+ for (const [index, entry] of entries.entries()) {
15084
+ result.push(
15085
+ this.parseSpecializedClassRelation(
15086
+ info,
15087
+ field,
15088
+ entry,
15089
+ group.relationKind,
15090
+ group.ordered ? index : null,
15091
+ `${group.property}-${index}`
15092
+ )
15093
+ );
15094
+ }
15095
+ continue;
15096
+ }
15097
+ if (raw !== void 0 && raw.kind !== "null") {
15098
+ result.push(
15099
+ this.parseSpecializedClassRelation(
15100
+ info,
15101
+ field,
15102
+ raw,
15103
+ group.relationKind,
15104
+ null,
15105
+ group.property
15106
+ )
15107
+ );
15108
+ }
15109
+ }
15110
+ }
15111
+ const configurations = this.declarations.filter(
15112
+ (entry) => entry.declaration.kind === "relationConfiguration"
15113
+ );
15114
+ if (configurations.length > 1) {
15115
+ this.fail(
15116
+ "NEO3124",
15117
+ `At most one [NeoRelationConfiguration] declaration is allowed; found ${configurations.length}.`,
15118
+ configurations[1].declaration.location
15119
+ );
15120
+ }
15121
+ const configuration = configurations[0];
15122
+ if (configuration !== void 0) {
15123
+ if (!configuration.declaration.modifiers.includes("static")) {
15124
+ this.fail(
15125
+ "NEO3131",
15126
+ `[NeoRelationConfiguration] ${configuration.declaration.name} must be a static class.`,
15127
+ configuration.declaration.location
15128
+ );
15129
+ }
15130
+ const fields = configuration.declaration.members.filter(
15131
+ (member) => member.kind === "settings" && member.name === "NeoRelations"
15132
+ );
15133
+ if (fields.length !== 1 || fields[0]?.initializer === void 0) {
15134
+ this.fail(
15135
+ "NEO3125",
15136
+ `[NeoRelationConfiguration] ${configuration.declaration.name} must declare exactly one initialized static NeoRelations field.`,
15137
+ fields[0]?.location ?? configuration.declaration.location
15138
+ );
15139
+ }
15140
+ if (!fields[0].modifiers.includes("static")) {
15141
+ this.fail(
15142
+ "NEO3132",
15143
+ `[NeoRelationConfiguration] ${configuration.declaration.name}.NeoRelations must be static.`,
15144
+ fields[0].location
15145
+ );
15146
+ }
15147
+ const fieldType = parseTypeShape(fields[0].type ?? "");
15148
+ if (!fieldType.array || fieldType.arguments[0]?.name !== "NeoCompose.Schema.NeoInternalRecordRelationDefinition") {
15149
+ this.fail(
15150
+ "NEO3133",
15151
+ `[NeoRelationConfiguration] ${configuration.declaration.name}.NeoRelations must be NeoInternalRecordRelationDefinition[].`,
15152
+ fields[0].location
15153
+ );
15154
+ }
15155
+ for (const [index, entry] of this.arrayValue(
15156
+ fields[0].initializer,
15157
+ "ProjectRelations.NeoRelations",
15158
+ fields[0].location
15159
+ ).entries()) {
15160
+ result.push(
15161
+ this.parseGenericInternalRecordRelation(
15162
+ entry,
15163
+ fields[0],
15164
+ `generic-${index}`
15165
+ )
15166
+ );
15167
+ }
15168
+ }
15169
+ const ids = /* @__PURE__ */ new Map();
15170
+ for (const relation of result) {
15171
+ const duplicate = ids.get(relation.id);
15172
+ if (duplicate !== void 0) {
15173
+ this.fail(
15174
+ "NEO3126",
15175
+ `Duplicate internal relation id ${JSON.stringify(relation.id)}.`,
15176
+ void 0
15177
+ );
15178
+ }
15179
+ ids.set(relation.id, relation);
15180
+ }
15181
+ return result;
15182
+ }
15183
+ parseSpecializedClassRelation(source, field, value, relationKind, order, pendingSuffix) {
15184
+ const definition2 = this.objectValue(
15185
+ value,
15186
+ "NeoClassRelationDefinition",
15187
+ field.location
15188
+ );
15189
+ const positional = definition2.items ?? [];
15190
+ const idValue = definition2.properties?.Id ?? (positional.length === 2 ? positional[0] : void 0);
15191
+ const targetValue = definition2.properties?.Target ?? (positional.length === 2 ? positional[1] : positional[0]);
15192
+ const targetName = this.typeOfArgument(
15193
+ targetValue,
15194
+ "NeoClassRelationDefinition.Target",
15195
+ field.location
15196
+ );
15197
+ if (targetName === void 0) {
15198
+ this.fail(
15199
+ "NEO3127",
15200
+ `Relation ${relationKind} requires a typeof(...) target.`,
15201
+ field.location
15202
+ );
15203
+ }
15204
+ const target = this.resolveDeclaration(this.classesByName, targetName);
15205
+ if (target === void 0) {
15206
+ this.fail(
15207
+ "NEO3128",
15208
+ `Relation ${relationKind} targets unknown Neo Class ${JSON.stringify(targetName)}.`,
15209
+ field.location
15210
+ );
15211
+ }
15212
+ const id = this.stringArgument(
15213
+ idValue,
15214
+ "NeoClassRelationDefinition.Id",
15215
+ field.location
15216
+ ) ?? pendingId("internal-record-relation", field.location, pendingSuffix);
15217
+ return {
15218
+ id,
15219
+ source: sourceIdentity(
15220
+ "internalRecordRelation",
15221
+ id,
15222
+ field.location,
15223
+ field.selectionLocation
15224
+ ),
15225
+ relationKind,
15226
+ sourceRecordKind: "class",
15227
+ sourceRecordId: source.id,
15228
+ targetRecordKind: "class",
15229
+ targetRecordId: target.id,
15230
+ order
15231
+ };
15232
+ }
15233
+ parseGenericInternalRecordRelation(value, field, pendingSuffix) {
15234
+ const definition2 = this.objectValue(
15235
+ value,
15236
+ "NeoInternalRecordRelationDefinition",
15237
+ field.location
15238
+ );
15239
+ const positional = definition2.items ?? [];
15240
+ if (positional.length !== 4) {
15241
+ this.fail(
15242
+ "NEO3129",
15243
+ "NeoInternalRecordRelationDefinition requires id, relation kind, source, and target constructor arguments.",
15244
+ field.location
15245
+ );
15246
+ }
15247
+ const id = this.stringArgument(positional[0], "relation id", field.location) ?? pendingId("internal-record-relation", field.location, pendingSuffix);
15248
+ return {
15249
+ id,
15250
+ source: sourceIdentity(
15251
+ "internalRecordRelation",
15252
+ id,
15253
+ field.location,
15254
+ field.selectionLocation
15255
+ ),
15256
+ relationKind: this.requiredStringArgument(
15257
+ positional[1],
15258
+ "relation kind",
15259
+ field.location
15260
+ ),
15261
+ ...this.parseGenericRelationEndpoints(
15262
+ positional[2],
15263
+ positional[3],
15264
+ field.location
15265
+ ),
15266
+ order: null
15267
+ };
15268
+ }
15269
+ parseGenericRelationEndpoints(sourceValue, targetValue, location2) {
15270
+ const parse = (value, description) => {
15271
+ const reference = this.objectValue(value, description, location2);
15272
+ const positional = reference.items ?? [];
15273
+ const enumName = this.enumArgument(
15274
+ reference.properties?.Kind ?? positional[0],
15275
+ `${description}.Kind`,
15276
+ location2
15277
+ );
15278
+ const kind = enumName === void 0 ? void 0 : PROJECT_RECORD_KIND_BY_ENUM[enumName];
15279
+ if (kind === void 0) {
15280
+ this.fail(
15281
+ "NEO3130",
15282
+ `${description} has an unknown NeoProjectRecordKind.`,
15283
+ location2
15284
+ );
15285
+ }
15286
+ return {
15287
+ kind,
15288
+ id: this.requiredStringArgument(
15289
+ reference.properties?.Id ?? positional[1],
15290
+ `${description}.Id`,
15291
+ location2
15292
+ )
15293
+ };
15294
+ };
15295
+ const source = parse(sourceValue, "relation source");
15296
+ const target = parse(targetValue, "relation target");
15297
+ return {
15298
+ sourceRecordKind: source.kind,
15299
+ sourceRecordId: source.id,
15300
+ targetRecordKind: target.kind,
15301
+ targetRecordId: target.id
15302
+ };
15303
+ }
14523
15304
  compareMemberOrder(left, right) {
14524
15305
  const leftMarker = this.attribute(left.attributes, "NeoMember", false);
14525
15306
  const rightMarker = this.attribute(right.attributes, "NeoMember", false);
@@ -18209,6 +18990,26 @@ var init_document_contracts = __esm({
18209
18990
  "transitionToWhenSourceBecomesStatusId": "missingIsNull",
18210
18991
  "system": "nullIsAbsent"
18211
18992
  }
18993
+ },
18994
+ "internal-record-relation": {
18995
+ "authored": [
18996
+ "id",
18997
+ "relationKind",
18998
+ "sourceRecordKind",
18999
+ "sourceRecordId",
19000
+ "targetRecordKind",
19001
+ "targetRecordId",
19002
+ "orderKey"
19003
+ ],
19004
+ "derived": [],
19005
+ "volatile": [
19006
+ "projectId",
19007
+ "createdAt",
19008
+ "updatedAt"
19009
+ ],
19010
+ "normalization": {
19011
+ "orderKey": "nullIsAbsent"
19012
+ }
18212
19013
  }
18213
19014
  };
18214
19015
  }
@@ -19379,7 +20180,6 @@ function isSchemaSystemMetadata(value) {
19379
20180
  "replaceValue"
19380
20181
  ]);
19381
20182
  const worlds = /* @__PURE__ */ new Set([
19382
- "worldAssets",
19383
20183
  "tileGrid",
19384
20184
  "tileLayer",
19385
20185
  "objectLayer",
@@ -20171,22 +20971,283 @@ function schemaClassToDocument(schemaClass2) {
20171
20971
  extendsGenericBindings: schemaClass2.extendsGenericBindings
20172
20972
  });
20173
20973
  }
20174
- var CLASS_SCHEMA_RECORD_ADAPTER_V3;
20175
- var init_class = __esm({
20176
- "src/schema/manifest/record-adapters/class.ts"() {
20974
+ var CLASS_SCHEMA_RECORD_ADAPTER_V3;
20975
+ var init_class = __esm({
20976
+ "src/schema/manifest/record-adapters/class.ts"() {
20977
+ "use strict";
20978
+ init_contracts();
20979
+ init_codecs();
20980
+ CLASS_SCHEMA_RECORD_ADAPTER_V3 = {
20981
+ recordKind: "class",
20982
+ manifestCollection: "classes",
20983
+ cardinality: "many",
20984
+ fromDocument: schemaClassFromDocument,
20985
+ toAuthoredDocuments: (manifest) => manifest.classes.map((schemaClass2) => ({
20986
+ recordKind: "class",
20987
+ recordId: schemaClass2.id,
20988
+ authoredFields: schemaClassToDocument(schemaClass2)
20989
+ }))
20990
+ };
20991
+ }
20992
+ });
20993
+
20994
+ // src/schema/manifest/record-adapters/internal-record-relation.ts
20995
+ function internalRecordRelationFromDocument(record2, context) {
20996
+ const data = normalizeDocumentFieldsV3(
20997
+ "internal-record-relation",
20998
+ record2.data
20999
+ );
21000
+ const relationKind = requiredString(data, "relationKind", record2);
21001
+ const sourceRecordKind = projectRecordKind2(
21002
+ requiredString(data, "sourceRecordKind", record2),
21003
+ record2,
21004
+ "sourceRecordKind"
21005
+ );
21006
+ const sourceRecordId = requiredString(data, "sourceRecordId", record2);
21007
+ const orderKey = optionalStringOrNull(data.orderKey);
21008
+ const order = orderKey === null ? null : orderedDirectGroup(context, {
21009
+ relationKind,
21010
+ sourceRecordKind,
21011
+ sourceRecordId
21012
+ }).findIndex((candidate) => candidate.recordId === record2.recordId);
21013
+ if (orderKey !== null && (order === null || order < 0)) {
21014
+ throw new Error(
21015
+ `Internal relation ${record2.recordId} could not be located in its ordered direct source set.`
21016
+ );
21017
+ }
21018
+ return {
21019
+ id: record2.recordId,
21020
+ source: context.sourceForRecord(
21021
+ "internal-record-relation",
21022
+ record2.recordId,
21023
+ "internalRecordRelation"
21024
+ ),
21025
+ relationKind,
21026
+ sourceRecordKind,
21027
+ sourceRecordId,
21028
+ targetRecordKind: projectRecordKind2(
21029
+ requiredString(data, "targetRecordKind", record2),
21030
+ record2,
21031
+ "targetRecordKind"
21032
+ ),
21033
+ targetRecordId: requiredString(data, "targetRecordId", record2),
21034
+ order
21035
+ };
21036
+ }
21037
+ function orderedDirectGroup(context, source) {
21038
+ return [...context.recordsByKind.get("internal-record-relation") ?? []].filter((candidate) => {
21039
+ const data = normalizeDocumentFieldsV3(
21040
+ "internal-record-relation",
21041
+ candidate.data
21042
+ );
21043
+ return data.relationKind === source.relationKind && data.sourceRecordKind === source.sourceRecordKind && data.sourceRecordId === source.sourceRecordId && typeof data.orderKey === "string";
21044
+ }).sort((left, right) => {
21045
+ const leftData = normalizeDocumentFieldsV3(
21046
+ "internal-record-relation",
21047
+ left.data
21048
+ );
21049
+ const rightData = normalizeDocumentFieldsV3(
21050
+ "internal-record-relation",
21051
+ right.data
21052
+ );
21053
+ return String(leftData.orderKey).localeCompare(String(rightData.orderKey)) || left.recordId.localeCompare(right.recordId);
21054
+ });
21055
+ }
21056
+ function internalRecordRelationToDocument(relation, orderKey) {
21057
+ return omitUndefined({
21058
+ id: relation.id,
21059
+ relationKind: relation.relationKind,
21060
+ sourceRecordKind: relation.sourceRecordKind,
21061
+ sourceRecordId: relation.sourceRecordId,
21062
+ targetRecordKind: relation.targetRecordKind,
21063
+ targetRecordId: relation.targetRecordId,
21064
+ orderKey
21065
+ });
21066
+ }
21067
+ function relationOrderKeys(manifest, context) {
21068
+ const result = /* @__PURE__ */ new Map();
21069
+ const groups = /* @__PURE__ */ new Map();
21070
+ for (const relation of manifest.internalRecordRelations) {
21071
+ if (relation.order === null) continue;
21072
+ const key = `${relation.relationKind}\0${relation.sourceRecordKind}\0${relation.sourceRecordId}`;
21073
+ const group = groups.get(key) ?? [];
21074
+ group.push(relation);
21075
+ groups.set(key, group);
21076
+ }
21077
+ for (const group of groups.values()) {
21078
+ group.sort(
21079
+ (left, right) => (left.order ?? 0) - (right.order ?? 0) || left.id.localeCompare(right.id)
21080
+ );
21081
+ const groupSource = group[0];
21082
+ const base = group.map(
21083
+ (relation) => context.baseRecord("internal-record-relation", relation.id)
21084
+ ).filter((record2) => record2 !== null).filter((record2) => {
21085
+ if (groupSource === void 0) return false;
21086
+ const data = normalizeDocumentFieldsV3(
21087
+ "internal-record-relation",
21088
+ record2.data
21089
+ );
21090
+ return data.relationKind === groupSource.relationKind && data.sourceRecordKind === groupSource.sourceRecordKind && data.sourceRecordId === groupSource.sourceRecordId;
21091
+ }).map((record2) => ({
21092
+ id: record2.recordId,
21093
+ key: typeof record2.data.orderKey === "string" ? record2.data.orderKey : null
21094
+ })).filter(
21095
+ (entry) => entry.key !== null
21096
+ ).sort((left, right) => left.key.localeCompare(right.key));
21097
+ const unchanged = base.length === group.length && group.every((relation, index) => relation.id === base[index]?.id);
21098
+ if (unchanged) {
21099
+ for (const entry of base) result.set(entry.id, entry.key);
21100
+ continue;
21101
+ }
21102
+ const baseIds = base.map((entry) => entry.id);
21103
+ const desiredIds = group.map((relation) => relation.id);
21104
+ const anchoredIds = new Set(longestCommonSubsequence(baseIds, desiredIds));
21105
+ const baseKeysById = new Map(base.map((entry) => [entry.id, entry.key]));
21106
+ for (const id of anchoredIds) {
21107
+ const key = baseKeysById.get(id);
21108
+ if (key !== void 0) result.set(id, key);
21109
+ }
21110
+ const assignedKeys = new Set(
21111
+ [...anchoredIds].map((id) => baseKeysById.get(id)).filter((key) => key !== void 0)
21112
+ );
21113
+ let failedToAllocate = false;
21114
+ for (const [index, relation] of group.entries()) {
21115
+ if (result.has(relation.id)) continue;
21116
+ const previousKey = findAssignedNeighborKey(group, index, -1, result);
21117
+ const nextKey = findAssignedNeighborKey(group, index, 1, result);
21118
+ const key = relationKeyBetween(previousKey, nextKey, assignedKeys);
21119
+ if (key === null) {
21120
+ failedToAllocate = true;
21121
+ break;
21122
+ }
21123
+ result.set(relation.id, key);
21124
+ assignedKeys.add(key);
21125
+ }
21126
+ if (failedToAllocate) {
21127
+ for (const relation of group) result.delete(relation.id);
21128
+ for (const [index, relation] of group.entries()) {
21129
+ result.set(relation.id, String((index + 1) * 1024).padStart(12, "0"));
21130
+ }
21131
+ }
21132
+ }
21133
+ return result;
21134
+ }
21135
+ function longestCommonSubsequence(left, right) {
21136
+ const lengths = Array.from(
21137
+ { length: left.length + 1 },
21138
+ () => Array(right.length + 1).fill(0)
21139
+ );
21140
+ for (let leftIndex2 = left.length - 1; leftIndex2 >= 0; leftIndex2 -= 1) {
21141
+ for (let rightIndex2 = right.length - 1; rightIndex2 >= 0; rightIndex2 -= 1) {
21142
+ lengths[leftIndex2][rightIndex2] = left[leftIndex2] === right[rightIndex2] ? 1 + lengths[leftIndex2 + 1][rightIndex2 + 1] : Math.max(
21143
+ lengths[leftIndex2 + 1][rightIndex2],
21144
+ lengths[leftIndex2][rightIndex2 + 1]
21145
+ );
21146
+ }
21147
+ }
21148
+ const result = [];
21149
+ let leftIndex = 0;
21150
+ let rightIndex = 0;
21151
+ while (leftIndex < left.length && rightIndex < right.length) {
21152
+ if (left[leftIndex] === right[rightIndex]) {
21153
+ result.push(left[leftIndex]);
21154
+ leftIndex += 1;
21155
+ rightIndex += 1;
21156
+ } else if (lengths[leftIndex + 1][rightIndex] >= lengths[leftIndex][rightIndex + 1]) {
21157
+ leftIndex += 1;
21158
+ } else {
21159
+ rightIndex += 1;
21160
+ }
21161
+ }
21162
+ return result;
21163
+ }
21164
+ function findAssignedNeighborKey(group, startIndex, direction, assigned) {
21165
+ for (let index = startIndex + direction; index >= 0 && index < group.length; index += direction) {
21166
+ const relation = group[index];
21167
+ if (relation === void 0) continue;
21168
+ const key = assigned.get(relation.id);
21169
+ if (key !== void 0) return key;
21170
+ }
21171
+ return null;
21172
+ }
21173
+ function relationKeyBetween(previous, next, assigned) {
21174
+ if (previous === null && next === null) return "000000001024";
21175
+ if (previous !== null && next !== null && /^\d+$/.test(previous) && /^\d+$/.test(next) && previous.length === next.length) {
21176
+ const previousNumber = BigInt(previous);
21177
+ const nextNumber = BigInt(next);
21178
+ if (nextNumber - previousNumber > 1n) {
21179
+ const midpoint = (previousNumber + nextNumber) / 2n;
21180
+ const candidate = midpoint.toString().padStart(previous.length, "0");
21181
+ if (!assigned.has(candidate)) return candidate;
21182
+ }
21183
+ }
21184
+ if (previous === null && next !== null) {
21185
+ for (let depth = 1; depth <= 32; depth += 1) {
21186
+ const candidate = `${"!".repeat(depth)}${next}`;
21187
+ if (candidate.localeCompare(next) < 0 && !assigned.has(candidate)) {
21188
+ return candidate;
21189
+ }
21190
+ }
21191
+ return null;
21192
+ }
21193
+ if (previous !== null) {
21194
+ for (let depth = 1; depth <= 32; depth += 1) {
21195
+ const candidate = `${previous}${"~".repeat(depth)}`;
21196
+ if (candidate.localeCompare(previous) > 0 && (next === null || candidate.localeCompare(next) < 0) && !assigned.has(candidate)) {
21197
+ return candidate;
21198
+ }
21199
+ }
21200
+ }
21201
+ return null;
21202
+ }
21203
+ function projectRecordKind2(value, record2, field) {
21204
+ switch (value) {
21205
+ case "project":
21206
+ case "member":
21207
+ case "value":
21208
+ case "class":
21209
+ case "internal-record-relation":
21210
+ case "enum":
21211
+ case "interface":
21212
+ case "dialogue":
21213
+ case "dialogue-node":
21214
+ case "dialogue-group":
21215
+ case "priority-group":
21216
+ case "project-file":
21217
+ case "unity-texture-template":
21218
+ case "unity-audio-clip-template":
21219
+ case "localization-config":
21220
+ case "localization-status":
21221
+ case "localized-text":
21222
+ case "migration":
21223
+ return value;
21224
+ }
21225
+ throw new Error(
21226
+ `Schema document ${record2.recordKind}:${record2.recordId} field ${field} has unknown project record kind ${JSON.stringify(value)}.`
21227
+ );
21228
+ }
21229
+ var INTERNAL_RECORD_RELATION_SCHEMA_RECORD_ADAPTER_V3;
21230
+ var init_internal_record_relation = __esm({
21231
+ "src/schema/manifest/record-adapters/internal-record-relation.ts"() {
20177
21232
  "use strict";
20178
21233
  init_contracts();
20179
21234
  init_codecs();
20180
- CLASS_SCHEMA_RECORD_ADAPTER_V3 = {
20181
- recordKind: "class",
20182
- manifestCollection: "classes",
21235
+ INTERNAL_RECORD_RELATION_SCHEMA_RECORD_ADAPTER_V3 = {
21236
+ recordKind: "internal-record-relation",
21237
+ manifestCollection: "internalRecordRelations",
20183
21238
  cardinality: "many",
20184
- fromDocument: schemaClassFromDocument,
20185
- toAuthoredDocuments: (manifest) => manifest.classes.map((schemaClass2) => ({
20186
- recordKind: "class",
20187
- recordId: schemaClass2.id,
20188
- authoredFields: schemaClassToDocument(schemaClass2)
20189
- }))
21239
+ fromDocument: internalRecordRelationFromDocument,
21240
+ toAuthoredDocuments: (manifest, context) => {
21241
+ const orderKeys = relationOrderKeys(manifest, context);
21242
+ return manifest.internalRecordRelations.map((relation) => ({
21243
+ recordKind: "internal-record-relation",
21244
+ recordId: relation.id,
21245
+ authoredFields: internalRecordRelationToDocument(
21246
+ relation,
21247
+ orderKeys.get(relation.id) ?? null
21248
+ )
21249
+ }));
21250
+ }
20190
21251
  };
20191
21252
  }
20192
21253
  });
@@ -20202,6 +21263,7 @@ var init_registry = __esm({
20202
21263
  init_member();
20203
21264
  init_template();
20204
21265
  init_class();
21266
+ init_internal_record_relation();
20205
21267
  SCHEMA_RECORD_ADAPTER_REGISTRY_V3 = {
20206
21268
  member: MEMBER_SCHEMA_RECORD_ADAPTER_V3,
20207
21269
  class: CLASS_SCHEMA_RECORD_ADAPTER_V3,
@@ -20210,7 +21272,8 @@ var init_registry = __esm({
20210
21272
  "unity-texture-template": TEXTURE_TEMPLATE_SCHEMA_RECORD_ADAPTER_V3,
20211
21273
  "unity-audio-clip-template": AUDIO_TEMPLATE_SCHEMA_RECORD_ADAPTER_V3,
20212
21274
  "localization-config": LOCALIZATION_SCHEMA_RECORD_ADAPTER_V3,
20213
- "localization-status": LOCALIZATION_STATUS_SCHEMA_RECORD_ADAPTER_V3
21275
+ "localization-status": LOCALIZATION_STATUS_SCHEMA_RECORD_ADAPTER_V3,
21276
+ "internal-record-relation": INTERNAL_RECORD_RELATION_SCHEMA_RECORD_ADAPTER_V3
20214
21277
  };
20215
21278
  SCHEMA_RECORD_ADAPTERS_V3 = [
20216
21279
  SCHEMA_RECORD_ADAPTER_REGISTRY_V3.class,
@@ -20220,7 +21283,8 @@ var init_registry = __esm({
20220
21283
  SCHEMA_RECORD_ADAPTER_REGISTRY_V3["unity-texture-template"],
20221
21284
  SCHEMA_RECORD_ADAPTER_REGISTRY_V3["unity-audio-clip-template"],
20222
21285
  SCHEMA_RECORD_ADAPTER_REGISTRY_V3["localization-config"],
20223
- SCHEMA_RECORD_ADAPTER_REGISTRY_V3["localization-status"]
21286
+ SCHEMA_RECORD_ADAPTER_REGISTRY_V3["localization-status"],
21287
+ SCHEMA_RECORD_ADAPTER_REGISTRY_V3["internal-record-relation"]
20224
21288
  ];
20225
21289
  }
20226
21290
  });
@@ -20237,6 +21301,7 @@ var init_record_adapters = __esm({
20237
21301
  init_registry();
20238
21302
  init_template();
20239
21303
  init_class();
21304
+ init_internal_record_relation();
20240
21305
  }
20241
21306
  });
20242
21307
 
@@ -20255,7 +21320,8 @@ function documentsToSchemaManifestV3(records2, optionsOrContext = {}) {
20255
21320
  textureTemplates: [],
20256
21321
  audioTemplates: [],
20257
21322
  localization: void 0,
20258
- localizationStatuses: []
21323
+ localizationStatuses: [],
21324
+ internalRecordRelations: []
20259
21325
  };
20260
21326
  for (const adapter of SCHEMA_RECORD_ADAPTERS_V3) {
20261
21327
  const adapterRecords = context.recordsByKind.get(adapter.recordKind) ?? [];
@@ -20498,6 +21564,8 @@ function emitSchemaManifestV3(manifest) {
20498
21564
  }
20499
21565
  const loose = emitLooseMembers(context);
20500
21566
  if (loose !== null) append(loose);
21567
+ const genericRelations = emitGenericRelations(context);
21568
+ if (genericRelations !== null) append(genericRelations);
20501
21569
  append(emitLocalization(manifest.localization));
20502
21570
  for (const status of manifest.localizationStatuses) {
20503
21571
  append(
@@ -20875,6 +21943,14 @@ function emitNeoSchemaClass(context, schemaClass2) {
20875
21943
  if (typeBindingEntries.length > 0) {
20876
21944
  lines.push(...indent(typeBindingEntries));
20877
21945
  }
21946
+ const relationSettings = emitClassRelationSettings(context, schemaClass2);
21947
+ if (relationSettings.lines.length > 0) {
21948
+ if (typeBindingEntries.length > 0) lines.push("");
21949
+ lines.push(...indent(relationSettings.lines));
21950
+ for (const relationId of relationSettings.relationIds) {
21951
+ recordKeys.push(`internal-record-relation:${relationId}`);
21952
+ }
21953
+ }
20878
21954
  const orderedKeys2 = orderedSchemaKeys(schemaClass2);
20879
21955
  let emittedMember = false;
20880
21956
  for (const schemaKey of orderedKeys2) {
@@ -20886,7 +21962,9 @@ function emitNeoSchemaClass(context, schemaClass2) {
20886
21962
  `Class ${JSON.stringify(schemaClass2.name)} references missing member ${JSON.stringify(memberId)}.`
20887
21963
  );
20888
21964
  }
20889
- if (emittedMember || typeBindingEntries.length > 0) lines.push("");
21965
+ if (emittedMember || typeBindingEntries.length > 0 || relationSettings.lines.length > 0) {
21966
+ lines.push("");
21967
+ }
20890
21968
  const memberLines = emitMember(
20891
21969
  context,
20892
21970
  schemaClass2,
@@ -20912,6 +21990,119 @@ function emitNeoSchemaClass(context, schemaClass2) {
20912
21990
  [...new Set(recordKeys)]
20913
21991
  );
20914
21992
  }
21993
+ function emitClassRelationSettings(context, schemaClass2) {
21994
+ const relations = context.manifest.internalRecordRelations.filter(
21995
+ (relation) => relation.sourceRecordKind === "class" && relation.sourceRecordId === schemaClass2.id && relation.targetRecordKind === "class" && Object.hasOwn(SPECIALIZED_RELATION_EMISSION, relation.relationKind)
21996
+ );
21997
+ if (relations.length === 0) return { lines: [], relationIds: [] };
21998
+ const descriptors = relations.map((relation) => ({
21999
+ relation,
22000
+ descriptor: SPECIALIZED_RELATION_EMISSION[relation.relationKind]
22001
+ }));
22002
+ const settingsTypes = new Set(
22003
+ descriptors.map((entry) => entry.descriptor.settingsType)
22004
+ );
22005
+ if (settingsTypes.size !== 1) {
22006
+ throw new Error(
22007
+ `Class ${schemaClass2.id} has incompatible specialized relation families: ${[...settingsTypes].join(", ")}.`
22008
+ );
22009
+ }
22010
+ const settingsType = descriptors[0]?.descriptor.settingsType;
22011
+ if (settingsType === void 0) return { lines: [], relationIds: [] };
22012
+ const propertyOrder = [
22013
+ "TileImports",
22014
+ "ObjectImports",
22015
+ "TileLayers",
22016
+ "ObjectLayers",
22017
+ "CompatibleLayers",
22018
+ "DefaultLayer",
22019
+ "TargetLayer"
22020
+ ];
22021
+ const lines = [
22022
+ `private static readonly ${settingsType} NeoRelations = new()`,
22023
+ "{"
22024
+ ];
22025
+ for (const property2 of propertyOrder) {
22026
+ const entries = descriptors.filter(
22027
+ (entry) => entry.descriptor.property === property2
22028
+ );
22029
+ if (entries.length === 0) continue;
22030
+ const singleton = entries[0] !== void 0 && "singleton" in entries[0].descriptor && entries[0].descriptor.singleton === true;
22031
+ if (singleton) {
22032
+ if (entries.length !== 1) {
22033
+ throw new Error(
22034
+ `Class ${schemaClass2.id} declares more than one direct ${entries[0]?.relation.relationKind} relation.`
22035
+ );
22036
+ }
22037
+ lines.push(
22038
+ ` ${property2} = ${emitClassRelationDefinition(context, entries[0].relation)},`
22039
+ );
22040
+ continue;
22041
+ }
22042
+ entries.sort((left, right) => {
22043
+ if (left.descriptor.ordered) {
22044
+ return (left.relation.order ?? 0) - (right.relation.order ?? 0) || left.relation.id.localeCompare(right.relation.id);
22045
+ }
22046
+ return left.relation.targetRecordId.localeCompare(
22047
+ right.relation.targetRecordId
22048
+ ) || left.relation.id.localeCompare(right.relation.id);
22049
+ });
22050
+ lines.push(` ${property2} =`, " {");
22051
+ for (const entry of entries) {
22052
+ lines.push(
22053
+ ` ${emitClassRelationDefinition(context, entry.relation)},`
22054
+ );
22055
+ }
22056
+ lines.push(" },");
22057
+ }
22058
+ lines.push("};");
22059
+ return {
22060
+ lines,
22061
+ relationIds: relations.map((relation) => relation.id)
22062
+ };
22063
+ }
22064
+ function emitClassRelationDefinition(context, relation) {
22065
+ const target = requiredName(
22066
+ context.classNames,
22067
+ relation.targetRecordId,
22068
+ "relation target class"
22069
+ );
22070
+ return `new(${csString(relation.id)}, typeof(${target}))`;
22071
+ }
22072
+ function emitGenericRelations(context) {
22073
+ const relations = context.manifest.internalRecordRelations.filter(
22074
+ (relation) => !(relation.sourceRecordKind === "class" && relation.targetRecordKind === "class" && Object.hasOwn(SPECIALIZED_RELATION_EMISSION, relation.relationKind))
22075
+ ).sort(
22076
+ (left, right) => left.relationKind === right.relationKind ? left.id.localeCompare(right.id) : left.relationKind.localeCompare(right.relationKind)
22077
+ );
22078
+ if (relations.length === 0) return null;
22079
+ const ordered = relations.find((relation) => relation.order !== null);
22080
+ if (ordered !== void 0) {
22081
+ throw new Error(
22082
+ `Generic relation ${ordered.id} is ordered, but its relation kind has no typed source-owned settings contract. CLI contract upgrade required.`
22083
+ );
22084
+ }
22085
+ const lines = [
22086
+ "[NeoRelationConfiguration]",
22087
+ "internal static class ProjectRelations",
22088
+ "{",
22089
+ " internal static readonly NeoInternalRecordRelationDefinition[] NeoRelations =",
22090
+ " {",
22091
+ ...relations.map(
22092
+ (relation) => ` new(${csString(relation.id)}, ${csString(relation.relationKind)}, new(NeoProjectRecordKind.${enumCase(relation.sourceRecordKind)}, ${csString(relation.sourceRecordId)}), new(NeoProjectRecordKind.${enumCase(relation.targetRecordKind)}, ${csString(relation.targetRecordId)})),`
22093
+ ),
22094
+ " };",
22095
+ "}"
22096
+ ];
22097
+ return emitFile(
22098
+ "ProjectRelations.cs",
22099
+ [
22100
+ { recordKey: null, lines: HEADER.split("\n") },
22101
+ { recordKey: null, lines }
22102
+ ],
22103
+ relations.map((relation) => `internal-record-relation:${relation.id}`)
22104
+ );
22105
+ }
20915
22106
  function orderedSchemaKeys(schemaClass2) {
20916
22107
  const keys = Object.keys(schemaClass2.schema);
20917
22108
  const preferred = schemaClass2.schemaKeyOrder ?? [];
@@ -22278,7 +23469,7 @@ function emitLocalizationStatus(status, className) {
22278
23469
  [recordKey]
22279
23470
  );
22280
23471
  }
22281
- var HEADER;
23472
+ var HEADER, SPECIALIZED_RELATION_EMISSION;
22282
23473
  var init_emitter = __esm({
22283
23474
  "src/schema/emitter.ts"() {
22284
23475
  "use strict";
@@ -22295,6 +23486,62 @@ using System.Threading.Tasks;
22295
23486
 
22296
23487
  namespace ProjectSchema;
22297
23488
  `;
23489
+ SPECIALIZED_RELATION_EMISSION = {
23490
+ "world.grid.tile-import": {
23491
+ settingsType: "NeoGridRelationSettings",
23492
+ property: "TileImports",
23493
+ ordered: false
23494
+ },
23495
+ "world.grid.object-import": {
23496
+ settingsType: "NeoGridRelationSettings",
23497
+ property: "ObjectImports",
23498
+ ordered: false
23499
+ },
23500
+ "world.grid.tile-layer": {
23501
+ settingsType: "NeoGridRelationSettings",
23502
+ property: "TileLayers",
23503
+ ordered: true
23504
+ },
23505
+ "world.grid.object-layer": {
23506
+ settingsType: "NeoGridRelationSettings",
23507
+ property: "ObjectLayers",
23508
+ ordered: true
23509
+ },
23510
+ "world.tile.compatible-layer": {
23511
+ settingsType: "NeoTileRelationSettings",
23512
+ property: "CompatibleLayers",
23513
+ ordered: false
23514
+ },
23515
+ "world.tile.default-layer": {
23516
+ settingsType: "NeoTileRelationSettings",
23517
+ property: "DefaultLayer",
23518
+ ordered: false,
23519
+ singleton: true
23520
+ },
23521
+ "world.object.compatible-layer": {
23522
+ settingsType: "NeoObjectRelationSettings",
23523
+ property: "CompatibleLayers",
23524
+ ordered: false
23525
+ },
23526
+ "world.object.default-layer": {
23527
+ settingsType: "NeoObjectRelationSettings",
23528
+ property: "DefaultLayer",
23529
+ ordered: false,
23530
+ singleton: true
23531
+ },
23532
+ "world.tile-layer-link.target": {
23533
+ settingsType: "NeoTileLayerLinkRelationSettings",
23534
+ property: "TargetLayer",
23535
+ ordered: false,
23536
+ singleton: true
23537
+ },
23538
+ "world.object-layer-link.target": {
23539
+ settingsType: "NeoObjectLayerLinkRelationSettings",
23540
+ property: "TargetLayer",
23541
+ ordered: false,
23542
+ singleton: true
23543
+ }
23544
+ };
22298
23545
  }
22299
23546
  });
22300
23547
 
@@ -22375,7 +23622,8 @@ var init_project_documents = __esm({
22375
23622
  "unity-texture-template",
22376
23623
  "unity-audio-clip-template",
22377
23624
  "localization-config",
22378
- "localization-status"
23625
+ "localization-status",
23626
+ "internal-record-relation"
22379
23627
  ]);
22380
23628
  }
22381
23629
  });
@@ -22423,7 +23671,7 @@ function isSystemDisallowedOperation(value) {
22423
23671
  return value === SystemDisallowedOperation.EditRecord || value === SystemDisallowedOperation.DeleteRecord || value === SystemDisallowedOperation.SelectRecord || value === SystemDisallowedOperation.ReplaceValue;
22424
23672
  }
22425
23673
  function isNeoWorldSystemClassKind(value) {
22426
- return value === NeoWorldSystemClassKind.WorldAssets || value === NeoWorldSystemClassKind.TileGrid || value === NeoWorldSystemClassKind.TileLayer || value === NeoWorldSystemClassKind.ObjectLayer || value === NeoWorldSystemClassKind.Tile || value === NeoWorldSystemClassKind.ObjectBase || value === NeoWorldSystemClassKind.LayerGroupBase || value === NeoWorldSystemClassKind.SpriteObject || value === NeoWorldSystemClassKind.Object || value === NeoWorldSystemClassKind.TileLayerLink || value === NeoWorldSystemClassKind.ObjectLayerLink || value === NeoWorldSystemClassKind.ObjectPlacementTile || value === NeoWorldSystemClassKind.TileInstance || value === NeoWorldSystemClassKind.ObjectCollider || value === NeoWorldSystemClassKind.SortingLayer || value === NeoWorldSystemClassKind.SmartTile || value === NeoWorldSystemClassKind.SmartTileRule || value === NeoWorldSystemClassKind.SmartTileNeighbor;
23674
+ return value === NeoWorldSystemClassKind.TileGrid || value === NeoWorldSystemClassKind.TileLayer || value === NeoWorldSystemClassKind.ObjectLayer || value === NeoWorldSystemClassKind.Tile || value === NeoWorldSystemClassKind.ObjectBase || value === NeoWorldSystemClassKind.LayerGroupBase || value === NeoWorldSystemClassKind.SpriteObject || value === NeoWorldSystemClassKind.Object || value === NeoWorldSystemClassKind.TileLayerLink || value === NeoWorldSystemClassKind.ObjectLayerLink || value === NeoWorldSystemClassKind.ObjectPlacementTile || value === NeoWorldSystemClassKind.TileInstance || value === NeoWorldSystemClassKind.ObjectCollider || value === NeoWorldSystemClassKind.SortingLayer || value === NeoWorldSystemClassKind.SmartTile || value === NeoWorldSystemClassKind.SmartTileRule || value === NeoWorldSystemClassKind.SmartTileNeighbor;
22427
23675
  }
22428
23676
  function isSystemMetadata(value) {
22429
23677
  const v = value;
@@ -22465,7 +23713,6 @@ var init_core_types = __esm({
22465
23713
  ReplaceValue: "replaceValue"
22466
23714
  };
22467
23715
  NeoWorldSystemClassKind = {
22468
- WorldAssets: "worldAssets",
22469
23716
  TileGrid: "tileGrid",
22470
23717
  TileLayer: "tileLayer",
22471
23718
  ObjectLayer: "objectLayer",
@@ -27141,11 +28388,221 @@ var init_effective_storage = __esm({
27141
28388
  }
27142
28389
  });
27143
28390
 
27144
- // ../src/models/members/value-responses.ts
27145
- var init_value_responses = __esm({
27146
- "../src/models/members/value-responses.ts"() {
28391
+ // ../src/models/members/value-responses.ts
28392
+ var init_value_responses = __esm({
28393
+ "../src/models/members/value-responses.ts"() {
28394
+ "use strict";
28395
+ init_member_kinds();
28396
+ }
28397
+ });
28398
+
28399
+ // ../src/models/project/project-version-types.ts
28400
+ function isProjectVersionBumpKind(value) {
28401
+ if (value === ProjectVersionBumpKind.Patch) return true;
28402
+ if (value === ProjectVersionBumpKind.Minor) return true;
28403
+ if (value === ProjectVersionBumpKind.Major) return true;
28404
+ return false;
28405
+ }
28406
+ function isProjectDocumentRevisionMarker(value) {
28407
+ if (typeof value !== "object") return false;
28408
+ if (value === null) return false;
28409
+ const candidate = value;
28410
+ if (candidate.latestTransactionId !== null && typeof candidate.latestTransactionId !== "string") {
28411
+ return false;
28412
+ }
28413
+ if (typeof candidate.latestTransactionCreatedAt !== "number") return false;
28414
+ return typeof candidate.versionsStamp === "string";
28415
+ }
28416
+ function isProjectRecordKind(value) {
28417
+ if (value === ProjectRecordKind.Project) return true;
28418
+ if (value === ProjectRecordKind.Member) return true;
28419
+ if (value === ProjectRecordKind.Value) return true;
28420
+ if (value === ProjectRecordKind.Class) return true;
28421
+ if (value === ProjectRecordKind.InternalRecordRelation) return true;
28422
+ if (value === ProjectRecordKind.Enum) return true;
28423
+ if (value === ProjectRecordKind.Interface) return true;
28424
+ if (value === ProjectRecordKind.Dialogue) return true;
28425
+ if (value === ProjectRecordKind.DialogueNode) return true;
28426
+ if (value === ProjectRecordKind.DialogueGroup) return true;
28427
+ if (value === ProjectRecordKind.PriorityGroup) return true;
28428
+ if (value === ProjectRecordKind.ProjectFile) return true;
28429
+ if (value === ProjectRecordKind.UnityTextureTemplate) return true;
28430
+ if (value === ProjectRecordKind.UnityAudioClipTemplate) return true;
28431
+ if (value === ProjectRecordKind.LocalizationConfig) return true;
28432
+ if (value === ProjectRecordKind.LocalizationStatus) return true;
28433
+ if (value === ProjectRecordKind.LocalizedText) return true;
28434
+ if (value === ProjectRecordKind.Migration) return true;
28435
+ return false;
28436
+ }
28437
+ function isInternalRecordRelation(value) {
28438
+ if (!isWithId(value)) return false;
28439
+ const relation = value;
28440
+ if (!isString(relation.projectId)) return false;
28441
+ if (!isString(relation.relationKind)) return false;
28442
+ if (relation.relationKind.length === 0) return false;
28443
+ if (!isProjectRecordKind(relation.sourceRecordKind)) return false;
28444
+ if (!isString(relation.sourceRecordId)) return false;
28445
+ if (relation.sourceRecordId.length === 0) return false;
28446
+ if (!isProjectRecordKind(relation.targetRecordKind)) return false;
28447
+ if (!isString(relation.targetRecordId)) return false;
28448
+ if (relation.targetRecordId.length === 0) return false;
28449
+ if (relation.orderKey !== void 0 && (!isString(relation.orderKey) || relation.orderKey.length === 0)) {
28450
+ return false;
28451
+ }
28452
+ if (!isNumber(relation.createdAt)) return false;
28453
+ return isNumber(relation.updatedAt);
28454
+ }
28455
+ function isProjectVersionSemver(value) {
28456
+ if (!isObject(value)) return false;
28457
+ const v = value;
28458
+ if (!isNonNegativeInteger(v.major)) return false;
28459
+ if (!isNonNegativeInteger(v.minor)) return false;
28460
+ if (!isNonNegativeInteger(v.patch)) return false;
28461
+ if (!isString(v.label)) return false;
28462
+ return v.label === `${v.major}.${v.minor}.${v.patch}`;
28463
+ }
28464
+ function isProjectVersionProps(value) {
28465
+ if (!isWithId(value)) return false;
28466
+ const v = value;
28467
+ if (!isString(v.projectId)) return false;
28468
+ if (!isProjectVersionSemver(v.semver)) return false;
28469
+ if (!isString(v.statusId)) return false;
28470
+ if (!isProjectVersionBumpKind(v.bumpKind)) return false;
28471
+ if (!isNullableString(v.sourceVersionId)) return false;
28472
+ if (!isNullableString(v.sourceHeadVersionId)) return false;
28473
+ if (!isTimestamp(v.createdAt)) return false;
28474
+ if (!isTimestamp(v.updatedAt)) return false;
28475
+ if (!isOptionalNullableTimestamp(v.statusChangedAt)) return false;
28476
+ if (!isOptionalNullableTimestamp(v.releasedAt)) return false;
28477
+ if (!isOptionalNullableTimestamp(v.archivedAt)) return false;
28478
+ if (!isPositiveInteger(v.exportSchemaVersion)) return false;
28479
+ if (!isPositiveInteger(v.runtimeSchemaVersion)) return false;
28480
+ if (!isOptionalNullableString(v.codegenContractHash)) return false;
28481
+ if (v.kind !== void 0 && v.kind !== "branch" && v.kind !== "release") {
28482
+ return false;
28483
+ }
28484
+ if (!isOptionalNullableString(v.name)) return false;
28485
+ return isOptionalNullableString(v.runtimeDataContractHash);
28486
+ }
28487
+ function projectVersionDisplayLabel(version) {
28488
+ if (version.kind === "branch" && typeof version.name === "string") {
28489
+ return version.name;
28490
+ }
28491
+ return version.semver.label;
28492
+ }
28493
+ function isProjectVersion(value) {
28494
+ if (!isProjectVersionProps(value)) return false;
28495
+ return isWithId(value);
28496
+ }
28497
+ function isProjectVersionStatusProps(value) {
28498
+ if (!isWithId(value)) return false;
28499
+ const v = value;
28500
+ if (!isString(v.projectId)) return false;
28501
+ if (!isString(v.name)) return false;
28502
+ if (!isOptionalNullableString(v.description)) return false;
28503
+ if (!isNumber(v.sortOrder)) return false;
28504
+ if (!isOptionalNullableString(v.color)) return false;
28505
+ if (!isOptionalNullableTimestamp(v.archivedAt)) return false;
28506
+ if (!isTimestamp(v.createdAt)) return false;
28507
+ if (!isTimestamp(v.updatedAt)) return false;
28508
+ if (!isBoolean(v.isWritable)) return false;
28509
+ if (!isBoolean(v.canSourceNewVersions)) return false;
28510
+ if (!isStringArray(v.releaseChannelIds)) return false;
28511
+ if (!isStringArray(v.allowedNextStatusIds)) return false;
28512
+ if (v.system !== void 0 && v.system !== null) {
28513
+ return isSystemMetadata(v.system);
28514
+ }
28515
+ return true;
28516
+ }
28517
+ function isProjectVersionStatus(value) {
28518
+ if (!isProjectVersionStatusProps(value)) return false;
28519
+ return isWithId(value);
28520
+ }
28521
+ function isProjectReleaseChannelProps(value) {
28522
+ if (!isWithId(value)) return false;
28523
+ const v = value;
28524
+ if (!isString(v.projectId)) return false;
28525
+ if (!isString(v.name)) return false;
28526
+ if (!isString(v.slug)) return false;
28527
+ if (!isOptionalNullableString(v.description)) return false;
28528
+ if (!isNumber(v.sortOrder)) return false;
28529
+ if (!isTimestamp(v.createdAt)) return false;
28530
+ if (!isTimestamp(v.updatedAt)) return false;
28531
+ if (v.system !== void 0 && v.system !== null) {
28532
+ return isSystemMetadata(v.system);
28533
+ }
28534
+ return true;
28535
+ }
28536
+ function isProjectReleaseChannel(value) {
28537
+ if (!isProjectReleaseChannelProps(value)) return false;
28538
+ return isWithId(value);
28539
+ }
28540
+ function isNonNegativeInteger(value) {
28541
+ if (typeof value !== "number") return false;
28542
+ if (!Number.isInteger(value)) return false;
28543
+ return value >= 0;
28544
+ }
28545
+ function isPositiveInteger(value) {
28546
+ if (typeof value !== "number") return false;
28547
+ if (!Number.isInteger(value)) return false;
28548
+ return value > 0;
28549
+ }
28550
+ function isTimestamp(value) {
28551
+ if (typeof value !== "number") return false;
28552
+ return Number.isFinite(value);
28553
+ }
28554
+ function isNullableString(value) {
28555
+ if (value === null) return true;
28556
+ return isString(value);
28557
+ }
28558
+ function isOptionalNullableTimestamp(value) {
28559
+ if (value === void 0) return true;
28560
+ if (value === null) return true;
28561
+ return isTimestamp(value);
28562
+ }
28563
+ function isStringArray(value) {
28564
+ if (!Array.isArray(value)) return false;
28565
+ return value.every(isString);
28566
+ }
28567
+ var ProjectVersionBumpKind, ProjectRecordKind;
28568
+ var init_project_version_types = __esm({
28569
+ "../src/models/project/project-version-types.ts"() {
28570
+ "use strict";
28571
+ init_core();
28572
+ ProjectVersionBumpKind = {
28573
+ Patch: "patch",
28574
+ Minor: "minor",
28575
+ Major: "major"
28576
+ };
28577
+ ProjectRecordKind = {
28578
+ Project: "project",
28579
+ Member: "member",
28580
+ Value: "value",
28581
+ Class: "class",
28582
+ InternalRecordRelation: "internal-record-relation",
28583
+ Enum: "enum",
28584
+ Interface: "interface",
28585
+ Dialogue: "dialogue",
28586
+ DialogueNode: "dialogue-node",
28587
+ DialogueGroup: "dialogue-group",
28588
+ PriorityGroup: "priority-group",
28589
+ ProjectFile: "project-file",
28590
+ UnityTextureTemplate: "unity-texture-template",
28591
+ UnityAudioClipTemplate: "unity-audio-clip-template",
28592
+ LocalizationConfig: "localization-config",
28593
+ LocalizationStatus: "localization-status",
28594
+ LocalizedText: "localized-text",
28595
+ Migration: "migration"
28596
+ };
28597
+ }
28598
+ });
28599
+
28600
+ // ../src/models/project/initial-class-internal-record-relation.ts
28601
+ var init_initial_class_internal_record_relation = __esm({
28602
+ "../src/models/project/initial-class-internal-record-relation.ts"() {
27147
28603
  "use strict";
27148
- init_member_kinds();
28604
+ init_core();
28605
+ init_project_version_types();
27149
28606
  }
27150
28607
  });
27151
28608
 
@@ -27156,6 +28613,8 @@ var init_add_class_member = __esm({
27156
28613
  init_members();
27157
28614
  init_enum2();
27158
28615
  init_classes();
28616
+ init_initial_class_internal_record_relation();
28617
+ init_project_version_types();
27159
28618
  }
27160
28619
  });
27161
28620
 
@@ -28884,6 +30343,12 @@ function manifestRecordSources(manifest) {
28884
30343
  for (const status of manifest.localizationStatuses) {
28885
30344
  result.set(recordStateKey("localization-status", status.id), status.source);
28886
30345
  }
30346
+ for (const relation of manifest.internalRecordRelations) {
30347
+ result.set(
30348
+ recordStateKey("internal-record-relation", relation.id),
30349
+ relation.source
30350
+ );
30351
+ }
28887
30352
  return result;
28888
30353
  }
28889
30354
  function mergeMigrationServerFields(fileFields, baseData) {
@@ -28948,187 +30413,6 @@ var init_status = __esm({
28948
30413
  }
28949
30414
  });
28950
30415
 
28951
- // ../src/models/project/project-version-types.ts
28952
- function isProjectVersionBumpKind(value) {
28953
- if (value === ProjectVersionBumpKind.Patch) return true;
28954
- if (value === ProjectVersionBumpKind.Minor) return true;
28955
- if (value === ProjectVersionBumpKind.Major) return true;
28956
- return false;
28957
- }
28958
- function isProjectDocumentRevisionMarker(value) {
28959
- if (typeof value !== "object") return false;
28960
- if (value === null) return false;
28961
- const candidate = value;
28962
- if (candidate.latestTransactionId !== null && typeof candidate.latestTransactionId !== "string") {
28963
- return false;
28964
- }
28965
- if (typeof candidate.latestTransactionCreatedAt !== "number") return false;
28966
- return typeof candidate.versionsStamp === "string";
28967
- }
28968
- function isProjectRecordKind(value) {
28969
- if (value === ProjectRecordKind.Project) return true;
28970
- if (value === ProjectRecordKind.Member) return true;
28971
- if (value === ProjectRecordKind.Value) return true;
28972
- if (value === ProjectRecordKind.Class) return true;
28973
- if (value === ProjectRecordKind.Enum) return true;
28974
- if (value === ProjectRecordKind.Interface) return true;
28975
- if (value === ProjectRecordKind.Dialogue) return true;
28976
- if (value === ProjectRecordKind.DialogueNode) return true;
28977
- if (value === ProjectRecordKind.DialogueGroup) return true;
28978
- if (value === ProjectRecordKind.PriorityGroup) return true;
28979
- if (value === ProjectRecordKind.ProjectFile) return true;
28980
- if (value === ProjectRecordKind.UnityTextureTemplate) return true;
28981
- if (value === ProjectRecordKind.UnityAudioClipTemplate) return true;
28982
- if (value === ProjectRecordKind.LocalizationConfig) return true;
28983
- if (value === ProjectRecordKind.LocalizationStatus) return true;
28984
- if (value === ProjectRecordKind.LocalizedText) return true;
28985
- if (value === ProjectRecordKind.Migration) return true;
28986
- return false;
28987
- }
28988
- function isProjectVersionSemver(value) {
28989
- if (!isObject(value)) return false;
28990
- const v = value;
28991
- if (!isNonNegativeInteger(v.major)) return false;
28992
- if (!isNonNegativeInteger(v.minor)) return false;
28993
- if (!isNonNegativeInteger(v.patch)) return false;
28994
- if (!isString(v.label)) return false;
28995
- return v.label === `${v.major}.${v.minor}.${v.patch}`;
28996
- }
28997
- function isProjectVersionProps(value) {
28998
- if (!isWithId(value)) return false;
28999
- const v = value;
29000
- if (!isString(v.projectId)) return false;
29001
- if (!isProjectVersionSemver(v.semver)) return false;
29002
- if (!isString(v.statusId)) return false;
29003
- if (!isProjectVersionBumpKind(v.bumpKind)) return false;
29004
- if (!isNullableString(v.sourceVersionId)) return false;
29005
- if (!isNullableString(v.sourceHeadVersionId)) return false;
29006
- if (!isTimestamp(v.createdAt)) return false;
29007
- if (!isTimestamp(v.updatedAt)) return false;
29008
- if (!isOptionalNullableTimestamp(v.statusChangedAt)) return false;
29009
- if (!isOptionalNullableTimestamp(v.releasedAt)) return false;
29010
- if (!isOptionalNullableTimestamp(v.archivedAt)) return false;
29011
- if (!isPositiveInteger(v.exportSchemaVersion)) return false;
29012
- if (!isPositiveInteger(v.runtimeSchemaVersion)) return false;
29013
- if (!isOptionalNullableString(v.codegenContractHash)) return false;
29014
- if (v.kind !== void 0 && v.kind !== "branch" && v.kind !== "release") {
29015
- return false;
29016
- }
29017
- if (!isOptionalNullableString(v.name)) return false;
29018
- return isOptionalNullableString(v.runtimeDataContractHash);
29019
- }
29020
- function projectVersionDisplayLabel(version) {
29021
- if (version.kind === "branch" && typeof version.name === "string") {
29022
- return version.name;
29023
- }
29024
- return version.semver.label;
29025
- }
29026
- function isProjectVersion(value) {
29027
- if (!isProjectVersionProps(value)) return false;
29028
- return isWithId(value);
29029
- }
29030
- function isProjectVersionStatusProps(value) {
29031
- if (!isWithId(value)) return false;
29032
- const v = value;
29033
- if (!isString(v.projectId)) return false;
29034
- if (!isString(v.name)) return false;
29035
- if (!isOptionalNullableString(v.description)) return false;
29036
- if (!isNumber(v.sortOrder)) return false;
29037
- if (!isOptionalNullableString(v.color)) return false;
29038
- if (!isOptionalNullableTimestamp(v.archivedAt)) return false;
29039
- if (!isTimestamp(v.createdAt)) return false;
29040
- if (!isTimestamp(v.updatedAt)) return false;
29041
- if (!isBoolean(v.isWritable)) return false;
29042
- if (!isBoolean(v.canSourceNewVersions)) return false;
29043
- if (!isStringArray(v.releaseChannelIds)) return false;
29044
- if (!isStringArray(v.allowedNextStatusIds)) return false;
29045
- if (v.system !== void 0 && v.system !== null) {
29046
- return isSystemMetadata(v.system);
29047
- }
29048
- return true;
29049
- }
29050
- function isProjectVersionStatus(value) {
29051
- if (!isProjectVersionStatusProps(value)) return false;
29052
- return isWithId(value);
29053
- }
29054
- function isProjectReleaseChannelProps(value) {
29055
- if (!isWithId(value)) return false;
29056
- const v = value;
29057
- if (!isString(v.projectId)) return false;
29058
- if (!isString(v.name)) return false;
29059
- if (!isString(v.slug)) return false;
29060
- if (!isOptionalNullableString(v.description)) return false;
29061
- if (!isNumber(v.sortOrder)) return false;
29062
- if (!isTimestamp(v.createdAt)) return false;
29063
- if (!isTimestamp(v.updatedAt)) return false;
29064
- if (v.system !== void 0 && v.system !== null) {
29065
- return isSystemMetadata(v.system);
29066
- }
29067
- return true;
29068
- }
29069
- function isProjectReleaseChannel(value) {
29070
- if (!isProjectReleaseChannelProps(value)) return false;
29071
- return isWithId(value);
29072
- }
29073
- function isNonNegativeInteger(value) {
29074
- if (typeof value !== "number") return false;
29075
- if (!Number.isInteger(value)) return false;
29076
- return value >= 0;
29077
- }
29078
- function isPositiveInteger(value) {
29079
- if (typeof value !== "number") return false;
29080
- if (!Number.isInteger(value)) return false;
29081
- return value > 0;
29082
- }
29083
- function isTimestamp(value) {
29084
- if (typeof value !== "number") return false;
29085
- return Number.isFinite(value);
29086
- }
29087
- function isNullableString(value) {
29088
- if (value === null) return true;
29089
- return isString(value);
29090
- }
29091
- function isOptionalNullableTimestamp(value) {
29092
- if (value === void 0) return true;
29093
- if (value === null) return true;
29094
- return isTimestamp(value);
29095
- }
29096
- function isStringArray(value) {
29097
- if (!Array.isArray(value)) return false;
29098
- return value.every(isString);
29099
- }
29100
- var ProjectVersionBumpKind, ProjectRecordKind;
29101
- var init_project_version_types = __esm({
29102
- "../src/models/project/project-version-types.ts"() {
29103
- "use strict";
29104
- init_core();
29105
- ProjectVersionBumpKind = {
29106
- Patch: "patch",
29107
- Minor: "minor",
29108
- Major: "major"
29109
- };
29110
- ProjectRecordKind = {
29111
- Project: "project",
29112
- Member: "member",
29113
- Value: "value",
29114
- Class: "class",
29115
- Enum: "enum",
29116
- Interface: "interface",
29117
- Dialogue: "dialogue",
29118
- DialogueNode: "dialogue-node",
29119
- DialogueGroup: "dialogue-group",
29120
- PriorityGroup: "priority-group",
29121
- ProjectFile: "project-file",
29122
- UnityTextureTemplate: "unity-texture-template",
29123
- UnityAudioClipTemplate: "unity-audio-clip-template",
29124
- LocalizationConfig: "localization-config",
29125
- LocalizationStatus: "localization-status",
29126
- LocalizedText: "localized-text",
29127
- Migration: "migration"
29128
- };
29129
- }
29130
- });
29131
-
29132
30416
  // ../convex/_generated/api.js
29133
30417
  var api_exports = {};
29134
30418
  __export(api_exports, {
@@ -29319,6 +30603,144 @@ var init_project_migration_types = __esm({
29319
30603
  }
29320
30604
  });
29321
30605
 
30606
+ // ../src/models/project/internal-record-relations.ts
30607
+ function worldClassContract(relationKind, sourceWorldKind, targetWorldKind, targetClassPolicy, merge, allowAbstractTarget) {
30608
+ return {
30609
+ relationKind,
30610
+ endpointPairs: [{ sourceRecordKind: "class", targetRecordKind: "class" }],
30611
+ sourceClassPolicy: "include-descendants",
30612
+ targetClassPolicy,
30613
+ merge,
30614
+ allowCycles: false,
30615
+ sourceWorldKind,
30616
+ targetWorldKind,
30617
+ allowAbstractTarget
30618
+ };
30619
+ }
30620
+ var InternalRecordRelationKind, INTERNAL_RECORD_RELATION_KIND_CONTRACTS;
30621
+ var init_internal_record_relations = __esm({
30622
+ "../src/models/project/internal-record-relations.ts"() {
30623
+ "use strict";
30624
+ init_classes();
30625
+ init_core();
30626
+ init_project_version_types();
30627
+ InternalRecordRelationKind = {
30628
+ WorldGridTileImport: "world.grid.tile-import",
30629
+ WorldGridObjectImport: "world.grid.object-import",
30630
+ WorldGridTileLayer: "world.grid.tile-layer",
30631
+ WorldGridObjectLayer: "world.grid.object-layer",
30632
+ WorldTileCompatibleLayer: "world.tile.compatible-layer",
30633
+ WorldTileDefaultLayer: "world.tile.default-layer",
30634
+ WorldObjectCompatibleLayer: "world.object.compatible-layer",
30635
+ WorldObjectDefaultLayer: "world.object.default-layer",
30636
+ WorldTileLayerLinkTarget: "world.tile-layer-link.target",
30637
+ WorldObjectLayerLinkTarget: "world.object-layer-link.target",
30638
+ WorldSmartTileNeighborTile: "world.smart-tile-neighbor.tile"
30639
+ };
30640
+ INTERNAL_RECORD_RELATION_KIND_CONTRACTS = [
30641
+ worldClassContract(
30642
+ InternalRecordRelationKind.WorldGridTileImport,
30643
+ NeoWorldSystemClassKind.TileGrid,
30644
+ NeoWorldSystemClassKind.Tile,
30645
+ "include-descendants",
30646
+ "union",
30647
+ true
30648
+ ),
30649
+ worldClassContract(
30650
+ InternalRecordRelationKind.WorldGridObjectImport,
30651
+ NeoWorldSystemClassKind.TileGrid,
30652
+ NeoWorldSystemClassKind.Object,
30653
+ "include-descendants",
30654
+ "union",
30655
+ true
30656
+ ),
30657
+ worldClassContract(
30658
+ InternalRecordRelationKind.WorldGridTileLayer,
30659
+ NeoWorldSystemClassKind.TileGrid,
30660
+ NeoWorldSystemClassKind.TileLayer,
30661
+ "exact",
30662
+ "ordered-union",
30663
+ false
30664
+ ),
30665
+ worldClassContract(
30666
+ InternalRecordRelationKind.WorldGridObjectLayer,
30667
+ NeoWorldSystemClassKind.TileGrid,
30668
+ NeoWorldSystemClassKind.ObjectLayer,
30669
+ "exact",
30670
+ "ordered-union",
30671
+ false
30672
+ ),
30673
+ worldClassContract(
30674
+ InternalRecordRelationKind.WorldTileCompatibleLayer,
30675
+ NeoWorldSystemClassKind.Tile,
30676
+ NeoWorldSystemClassKind.TileLayer,
30677
+ "include-descendants",
30678
+ "union",
30679
+ true
30680
+ ),
30681
+ worldClassContract(
30682
+ InternalRecordRelationKind.WorldTileDefaultLayer,
30683
+ NeoWorldSystemClassKind.Tile,
30684
+ NeoWorldSystemClassKind.TileLayer,
30685
+ "exact",
30686
+ "nearest-single",
30687
+ false
30688
+ ),
30689
+ worldClassContract(
30690
+ InternalRecordRelationKind.WorldObjectCompatibleLayer,
30691
+ NeoWorldSystemClassKind.Object,
30692
+ NeoWorldSystemClassKind.ObjectLayer,
30693
+ "include-descendants",
30694
+ "union",
30695
+ true
30696
+ ),
30697
+ worldClassContract(
30698
+ InternalRecordRelationKind.WorldObjectDefaultLayer,
30699
+ NeoWorldSystemClassKind.Object,
30700
+ NeoWorldSystemClassKind.ObjectLayer,
30701
+ "exact",
30702
+ "nearest-single",
30703
+ false
30704
+ ),
30705
+ worldClassContract(
30706
+ InternalRecordRelationKind.WorldTileLayerLinkTarget,
30707
+ NeoWorldSystemClassKind.TileLayerLink,
30708
+ NeoWorldSystemClassKind.TileLayer,
30709
+ "exact",
30710
+ "nearest-single",
30711
+ false
30712
+ ),
30713
+ worldClassContract(
30714
+ InternalRecordRelationKind.WorldObjectLayerLinkTarget,
30715
+ NeoWorldSystemClassKind.ObjectLayerLink,
30716
+ NeoWorldSystemClassKind.ObjectLayer,
30717
+ "exact",
30718
+ "nearest-single",
30719
+ false
30720
+ ),
30721
+ {
30722
+ relationKind: InternalRecordRelationKind.WorldSmartTileNeighborTile,
30723
+ endpointPairs: [{ sourceRecordKind: "value", targetRecordKind: "class" }],
30724
+ sourceClassPolicy: "exact",
30725
+ targetClassPolicy: "exact",
30726
+ merge: "nearest-single",
30727
+ allowCycles: false,
30728
+ sourceWorldKind: NeoWorldSystemClassKind.SmartTileNeighbor,
30729
+ targetWorldKind: NeoWorldSystemClassKind.Tile,
30730
+ allowAbstractTarget: true
30731
+ }
30732
+ ];
30733
+ }
30734
+ });
30735
+
30736
+ // ../src/models/project/internal-record-relation-head-projection.ts
30737
+ var init_internal_record_relation_head_projection = __esm({
30738
+ "../src/models/project/internal-record-relation-head-projection.ts"() {
30739
+ "use strict";
30740
+ init_project_version_types();
30741
+ }
30742
+ });
30743
+
29322
30744
  // ../src/models/project/index.ts
29323
30745
  var init_project2 = __esm({
29324
30746
  "../src/models/project/index.ts"() {
@@ -29328,6 +30750,9 @@ var init_project2 = __esm({
29328
30750
  init_project_root_members();
29329
30751
  init_project_version_types();
29330
30752
  init_project_migration_types();
30753
+ init_internal_record_relations();
30754
+ init_internal_record_relation_head_projection();
30755
+ init_initial_class_internal_record_relation();
29331
30756
  }
29332
30757
  });
29333
30758
 
@@ -30223,6 +31648,7 @@ var init_projectRecordBuckets = __esm({
30223
31648
  member: "members",
30224
31649
  value: "values",
30225
31650
  class: "classes",
31651
+ "internal-record-relation": "internalRecordRelations",
30226
31652
  enum: "enums",
30227
31653
  interface: "interfaces",
30228
31654
  dialogue: "dialogueRecords",
@@ -30618,6 +32044,7 @@ var init_project_record_migrations = __esm({
30618
32044
  [ProjectRecordKind.Member]: 4,
30619
32045
  [ProjectRecordKind.Value]: 1,
30620
32046
  [ProjectRecordKind.Class]: 1,
32047
+ [ProjectRecordKind.InternalRecordRelation]: 1,
30621
32048
  [ProjectRecordKind.Enum]: 2,
30622
32049
  [ProjectRecordKind.Interface]: 1,
30623
32050
  [ProjectRecordKind.Dialogue]: 4,
@@ -30641,6 +32068,7 @@ var init_project_record_migrations = __esm({
30641
32068
  },
30642
32069
  [ProjectRecordKind.Value]: {},
30643
32070
  [ProjectRecordKind.Class]: {},
32071
+ [ProjectRecordKind.InternalRecordRelation]: {},
30644
32072
  [ProjectRecordKind.Enum]: {
30645
32073
  1: migrateEnumOptionKeyOrder
30646
32074
  },
@@ -31014,6 +32442,7 @@ function assembleProjectDocumentRaw(args) {
31014
32442
  project: null,
31015
32443
  members: [],
31016
32444
  classes: [],
32445
+ internalRecordRelations: [],
31017
32446
  values: [],
31018
32447
  enums: [],
31019
32448
  interfaces: [],
@@ -31074,6 +32503,7 @@ function assembleProjectDocumentRaw(args) {
31074
32503
  project: buckets.project,
31075
32504
  members: buckets.members,
31076
32505
  classes: buckets.classes,
32506
+ internalRecordRelations: buckets.internalRecordRelations,
31077
32507
  values: buckets.values,
31078
32508
  enums: buckets.enums,
31079
32509
  interfaces: buckets.interfaces,
@@ -31154,6 +32584,11 @@ function readProjectDocument(value, options = {}) {
31154
32584
  isAnyMember
31155
32585
  ),
31156
32586
  classes: readArrayField(value, "classes", isNeoSchemaClass),
32587
+ internalRecordRelations: readOptionalArrayField(
32588
+ value,
32589
+ "internalRecordRelations",
32590
+ isInternalRecordRelation
32591
+ ),
31157
32592
  values: readArrayField(value, "values", isMemberValue),
31158
32593
  enums: readArrayField(value, "enums", isEnum),
31159
32594
  interfaces: readArrayField(value, "interfaces", isNeoInterface),
@@ -31380,6 +32815,12 @@ async function fetchProjectDocument(workspace) {
31380
32815
  entries: readRawArray(raw, "localizationStatuses"),
31381
32816
  guard: isProjectedRecord,
31382
32817
  label: "localization status"
32818
+ },
32819
+ {
32820
+ recordKind: "internal-record-relation",
32821
+ entries: readRawArray(raw, "internalRecordRelations"),
32822
+ guard: isProjectedRecord,
32823
+ label: "internal record relation"
31383
32824
  }
31384
32825
  ];
31385
32826
  const records2 = /* @__PURE__ */ new Map();
@@ -33032,6 +34473,9 @@ var init_project_version_intents = __esm({
33032
34473
  ClassUpdate: "class.update",
33033
34474
  ClassDelete: "class.delete",
33034
34475
  ClassAddSchemaEntry: "class.add-schema-entry",
34476
+ InternalRecordRelationCreate: "internal-record-relation.create",
34477
+ InternalRecordRelationUpdate: "internal-record-relation.update",
34478
+ InternalRecordRelationDelete: "internal-record-relation.delete",
33035
34479
  EnumCreate: "enum.create",
33036
34480
  EnumUpdate: "enum.update",
33037
34481
  EnumDelete: "enum.delete",