worldorbit 2.5.13 → 2.5.16
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/README.md +37 -11
- package/dist/browser/core/dist/index.js +1811 -386
- package/dist/browser/editor/dist/index.js +10534 -0
- package/dist/browser/markdown/dist/index.js +1477 -221
- package/dist/browser/viewer/dist/index.js +1569 -230
- package/dist/unpkg/core/dist/index.js +1814 -389
- package/dist/unpkg/editor/dist/index.js +10559 -0
- package/dist/unpkg/markdown/dist/index.js +1480 -224
- package/dist/unpkg/viewer/dist/index.js +1572 -233
- package/dist/unpkg/worldorbit-core.min.js +12 -5
- package/dist/unpkg/worldorbit-editor.min.js +812 -0
- package/dist/unpkg/worldorbit-markdown.min.js +32 -23
- package/dist/unpkg/worldorbit-viewer.min.js +55 -41
- package/dist/unpkg/worldorbit.js +1713 -231
- package/dist/unpkg/worldorbit.min.js +58 -44
- package/package.json +3 -2
- package/packages/core/README.md +5 -1
- package/packages/core/dist/atlas-edit.d.ts +2 -2
- package/packages/core/dist/atlas-edit.js +70 -7
- package/packages/core/dist/atlas-utils.d.ts +22 -0
- package/packages/core/dist/atlas-utils.js +189 -0
- package/packages/core/dist/atlas-validate.d.ts +2 -0
- package/packages/core/dist/atlas-validate.js +285 -0
- package/packages/core/dist/draft-parse.js +786 -153
- package/packages/core/dist/draft.d.ts +3 -0
- package/packages/core/dist/draft.js +47 -3
- package/packages/core/dist/format.js +165 -9
- package/packages/core/dist/load.js +58 -13
- package/packages/core/dist/normalize.js +7 -0
- package/packages/core/dist/scene.js +66 -13
- package/packages/core/dist/types.d.ts +97 -3
- package/packages/editor/dist/editor.js +44 -0
- package/packages/markdown/README.md +1 -1
- package/packages/viewer/README.md +2 -1
- package/packages/viewer/dist/atlas-state.js +7 -1
- package/packages/viewer/dist/atlas-viewer.js +35 -1
- package/packages/viewer/dist/render.js +16 -7
- package/packages/viewer/dist/theme.js +4 -0
- package/packages/viewer/dist/tooltip.js +35 -0
- package/packages/viewer/dist/types.d.ts +7 -0
- package/packages/viewer/dist/viewer.js +4 -0
package/dist/unpkg/worldorbit.js
CHANGED
|
@@ -643,7 +643,10 @@ var WorldOrbit = (() => {
|
|
|
643
643
|
return {
|
|
644
644
|
format: "worldorbit",
|
|
645
645
|
version: "1.0",
|
|
646
|
+
schemaVersion: "1.0",
|
|
646
647
|
system,
|
|
648
|
+
groups: [],
|
|
649
|
+
relations: [],
|
|
647
650
|
objects
|
|
648
651
|
};
|
|
649
652
|
}
|
|
@@ -653,13 +656,17 @@ var WorldOrbit = (() => {
|
|
|
653
656
|
const fieldMap = collectFields(mergedFields);
|
|
654
657
|
const placement = extractPlacement(node.objectType, fieldMap);
|
|
655
658
|
const properties = normalizeProperties(fieldMap);
|
|
656
|
-
const
|
|
659
|
+
const info2 = normalizeInfo(node.infoEntries);
|
|
657
660
|
if (node.objectType === "system") {
|
|
658
661
|
return {
|
|
659
662
|
type: "system",
|
|
660
663
|
id: node.name,
|
|
664
|
+
title: typeof properties.title === "string" ? properties.title : null,
|
|
665
|
+
description: null,
|
|
666
|
+
epoch: null,
|
|
667
|
+
referencePlane: null,
|
|
661
668
|
properties,
|
|
662
|
-
info
|
|
669
|
+
info: info2
|
|
663
670
|
};
|
|
664
671
|
}
|
|
665
672
|
return {
|
|
@@ -667,7 +674,7 @@ var WorldOrbit = (() => {
|
|
|
667
674
|
id: node.name,
|
|
668
675
|
properties,
|
|
669
676
|
placement,
|
|
670
|
-
info
|
|
677
|
+
info: info2
|
|
671
678
|
};
|
|
672
679
|
}
|
|
673
680
|
function validateFieldCompatibility(objectType, fields) {
|
|
@@ -797,14 +804,14 @@ var WorldOrbit = (() => {
|
|
|
797
804
|
}
|
|
798
805
|
}
|
|
799
806
|
function normalizeInfo(entries) {
|
|
800
|
-
const
|
|
807
|
+
const info2 = {};
|
|
801
808
|
for (const entry of entries) {
|
|
802
|
-
if (entry.key in
|
|
809
|
+
if (entry.key in info2) {
|
|
803
810
|
throw WorldOrbitError.fromLocation(`Duplicate info key "${entry.key}"`, entry.location);
|
|
804
811
|
}
|
|
805
|
-
|
|
812
|
+
info2[entry.key] = entry.value;
|
|
806
813
|
}
|
|
807
|
-
return
|
|
814
|
+
return info2;
|
|
808
815
|
}
|
|
809
816
|
function parseAtReference(target, location) {
|
|
810
817
|
if (/^[A-Za-z0-9._-]+-[A-Za-z0-9._-]+:L\d+$/i.test(target)) {
|
|
@@ -978,38 +985,38 @@ var WorldOrbit = (() => {
|
|
|
978
985
|
function createDiagnostic(diagnostic) {
|
|
979
986
|
return { ...diagnostic };
|
|
980
987
|
}
|
|
981
|
-
function diagnosticFromError(
|
|
982
|
-
if (
|
|
988
|
+
function diagnosticFromError(error2, source, code = `${source}.failed`) {
|
|
989
|
+
if (error2 instanceof WorldOrbitError) {
|
|
983
990
|
return {
|
|
984
991
|
code,
|
|
985
992
|
severity: "error",
|
|
986
993
|
source,
|
|
987
|
-
message:
|
|
988
|
-
line:
|
|
989
|
-
column:
|
|
994
|
+
message: error2.message,
|
|
995
|
+
line: error2.line,
|
|
996
|
+
column: error2.column
|
|
990
997
|
};
|
|
991
998
|
}
|
|
992
|
-
if (
|
|
999
|
+
if (error2 instanceof Error) {
|
|
993
1000
|
return {
|
|
994
1001
|
code,
|
|
995
1002
|
severity: "error",
|
|
996
1003
|
source,
|
|
997
|
-
message:
|
|
1004
|
+
message: error2.message
|
|
998
1005
|
};
|
|
999
1006
|
}
|
|
1000
1007
|
return {
|
|
1001
1008
|
code,
|
|
1002
1009
|
severity: "error",
|
|
1003
1010
|
source,
|
|
1004
|
-
message: String(
|
|
1011
|
+
message: String(error2)
|
|
1005
1012
|
};
|
|
1006
1013
|
}
|
|
1007
1014
|
function parseWithDiagnostics(source) {
|
|
1008
1015
|
let ast;
|
|
1009
1016
|
try {
|
|
1010
1017
|
ast = parseWorldOrbit(source);
|
|
1011
|
-
} catch (
|
|
1012
|
-
const diagnostic = diagnosticFromError(
|
|
1018
|
+
} catch (error2) {
|
|
1019
|
+
const diagnostic = diagnosticFromError(error2, "parse");
|
|
1013
1020
|
return {
|
|
1014
1021
|
ok: false,
|
|
1015
1022
|
value: null,
|
|
@@ -1019,20 +1026,20 @@ var WorldOrbit = (() => {
|
|
|
1019
1026
|
let document2;
|
|
1020
1027
|
try {
|
|
1021
1028
|
document2 = normalizeDocument(ast);
|
|
1022
|
-
} catch (
|
|
1029
|
+
} catch (error2) {
|
|
1023
1030
|
return {
|
|
1024
1031
|
ok: false,
|
|
1025
1032
|
value: null,
|
|
1026
|
-
diagnostics: [diagnosticFromError(
|
|
1033
|
+
diagnostics: [diagnosticFromError(error2, "normalize")]
|
|
1027
1034
|
};
|
|
1028
1035
|
}
|
|
1029
1036
|
try {
|
|
1030
1037
|
validateDocument(document2);
|
|
1031
|
-
} catch (
|
|
1038
|
+
} catch (error2) {
|
|
1032
1039
|
return {
|
|
1033
1040
|
ok: false,
|
|
1034
1041
|
value: null,
|
|
1035
|
-
diagnostics: [diagnosticFromError(
|
|
1042
|
+
diagnostics: [diagnosticFromError(error2, "validate")]
|
|
1036
1043
|
};
|
|
1037
1044
|
}
|
|
1038
1045
|
return {
|
|
@@ -1051,11 +1058,11 @@ var WorldOrbit = (() => {
|
|
|
1051
1058
|
value: normalizeDocument(ast),
|
|
1052
1059
|
diagnostics: []
|
|
1053
1060
|
};
|
|
1054
|
-
} catch (
|
|
1061
|
+
} catch (error2) {
|
|
1055
1062
|
return {
|
|
1056
1063
|
ok: false,
|
|
1057
1064
|
value: null,
|
|
1058
|
-
diagnostics: [diagnosticFromError(
|
|
1065
|
+
diagnostics: [diagnosticFromError(error2, "normalize")]
|
|
1059
1066
|
};
|
|
1060
1067
|
}
|
|
1061
1068
|
}
|
|
@@ -1067,11 +1074,11 @@ var WorldOrbit = (() => {
|
|
|
1067
1074
|
value: document2,
|
|
1068
1075
|
diagnostics: []
|
|
1069
1076
|
};
|
|
1070
|
-
} catch (
|
|
1077
|
+
} catch (error2) {
|
|
1071
1078
|
return {
|
|
1072
1079
|
ok: false,
|
|
1073
1080
|
value: null,
|
|
1074
|
-
diagnostics: [diagnosticFromError(
|
|
1081
|
+
diagnostics: [diagnosticFromError(error2, "validate")]
|
|
1075
1082
|
};
|
|
1076
1083
|
}
|
|
1077
1084
|
}
|
|
@@ -1203,8 +1210,10 @@ var WorldOrbit = (() => {
|
|
|
1203
1210
|
const orbitVisuals = orbitDrafts.map((draft) => createOrbitVisual(draft, relationships.groupIds.get(draft.object.id) ?? null));
|
|
1204
1211
|
const leaders = leaderDrafts.map((draft) => createLeaderLine(draft));
|
|
1205
1212
|
const labels = createSceneLabels(objects, height, scaleModel.labelMultiplier);
|
|
1206
|
-
const
|
|
1213
|
+
const relations = createSceneRelations(document2, objects);
|
|
1214
|
+
const layers = createSceneLayers(orbitVisuals, relations, leaders, objects, labels);
|
|
1207
1215
|
const groups = createSceneGroups(objects, orbitVisuals, leaders, labels, relationships);
|
|
1216
|
+
const semanticGroups = createSceneSemanticGroups(document2, objects);
|
|
1208
1217
|
const viewpoints = createSceneViewpoints(document2, projection, frame.preset, relationships, objectMap);
|
|
1209
1218
|
const contentBounds = calculateContentBounds(width, height, objects, orbitVisuals, leaders, labels);
|
|
1210
1219
|
return {
|
|
@@ -1214,7 +1223,7 @@ var WorldOrbit = (() => {
|
|
|
1214
1223
|
renderPreset: frame.preset,
|
|
1215
1224
|
projection,
|
|
1216
1225
|
scaleModel,
|
|
1217
|
-
title: String(document2.system?.properties.title ?? document2.system?.id ?? "WorldOrbit") || "WorldOrbit",
|
|
1226
|
+
title: String(document2.system?.title ?? document2.system?.properties.title ?? document2.system?.id ?? "WorldOrbit") || "WorldOrbit",
|
|
1218
1227
|
subtitle: `${capitalizeLabel(projection)} view - ${capitalizeLabel(layoutPreset)} layout`,
|
|
1219
1228
|
systemId,
|
|
1220
1229
|
viewMode: projection,
|
|
@@ -1230,9 +1239,11 @@ var WorldOrbit = (() => {
|
|
|
1230
1239
|
contentBounds,
|
|
1231
1240
|
layers,
|
|
1232
1241
|
groups,
|
|
1242
|
+
semanticGroups,
|
|
1233
1243
|
viewpoints,
|
|
1234
1244
|
objects,
|
|
1235
1245
|
orbitVisuals,
|
|
1246
|
+
relations,
|
|
1236
1247
|
leaders,
|
|
1237
1248
|
labels
|
|
1238
1249
|
};
|
|
@@ -1342,6 +1353,7 @@ var WorldOrbit = (() => {
|
|
|
1342
1353
|
}
|
|
1343
1354
|
function createSceneObject(position, scaleModel, relationships) {
|
|
1344
1355
|
const { object, x, y, radius, sortKey, anchorX, anchorY } = position;
|
|
1356
|
+
const renderPriority = object.renderHints?.renderPriority ?? 0;
|
|
1345
1357
|
return {
|
|
1346
1358
|
renderId: createRenderId(object.id),
|
|
1347
1359
|
objectId: object.id,
|
|
@@ -1350,11 +1362,12 @@ var WorldOrbit = (() => {
|
|
|
1350
1362
|
ancestorIds: relationships.ancestorIds.get(object.id) ?? [],
|
|
1351
1363
|
childIds: relationships.childIds.get(object.id) ?? [],
|
|
1352
1364
|
groupId: relationships.groupIds.get(object.id) ?? null,
|
|
1365
|
+
semanticGroupIds: [...object.groups ?? []],
|
|
1353
1366
|
x,
|
|
1354
1367
|
y,
|
|
1355
1368
|
radius,
|
|
1356
1369
|
visualRadius: visualExtentForObject(object, radius, scaleModel),
|
|
1357
|
-
sortKey,
|
|
1370
|
+
sortKey: sortKey + renderPriority * 1e-3,
|
|
1358
1371
|
anchorX,
|
|
1359
1372
|
anchorY,
|
|
1360
1373
|
label: object.id,
|
|
@@ -1371,6 +1384,7 @@ var WorldOrbit = (() => {
|
|
|
1371
1384
|
object: draft.object,
|
|
1372
1385
|
parentId: draft.parentId,
|
|
1373
1386
|
groupId,
|
|
1387
|
+
semanticGroupIds: [...draft.object.groups ?? []],
|
|
1374
1388
|
kind: draft.kind,
|
|
1375
1389
|
cx: draft.cx,
|
|
1376
1390
|
cy: draft.cy,
|
|
@@ -1382,7 +1396,7 @@ var WorldOrbit = (() => {
|
|
|
1382
1396
|
bandThickness: draft.bandThickness,
|
|
1383
1397
|
frontArcPath: draft.frontArcPath,
|
|
1384
1398
|
backArcPath: draft.backArcPath,
|
|
1385
|
-
hidden: draft.object.properties.hidden === true
|
|
1399
|
+
hidden: draft.object.properties.hidden === true || draft.object.renderHints?.renderOrbit === false
|
|
1386
1400
|
};
|
|
1387
1401
|
}
|
|
1388
1402
|
function createLeaderLine(draft) {
|
|
@@ -1391,6 +1405,7 @@ var WorldOrbit = (() => {
|
|
|
1391
1405
|
objectId: draft.object.id,
|
|
1392
1406
|
object: draft.object,
|
|
1393
1407
|
groupId: draft.groupId,
|
|
1408
|
+
semanticGroupIds: [...draft.object.groups ?? []],
|
|
1394
1409
|
x1: draft.x1,
|
|
1395
1410
|
y1: draft.y1,
|
|
1396
1411
|
x2: draft.x2,
|
|
@@ -1402,7 +1417,7 @@ var WorldOrbit = (() => {
|
|
|
1402
1417
|
function createSceneLabels(objects, sceneHeight, labelMultiplier) {
|
|
1403
1418
|
const labels = [];
|
|
1404
1419
|
const occupied = [];
|
|
1405
|
-
const visibleObjects = [...objects].filter((object) => !object.hidden).sort((left, right) => left.sortKey - right.sortKey);
|
|
1420
|
+
const visibleObjects = [...objects].filter((object) => !object.hidden && object.object.renderHints?.renderLabel !== false).sort((left, right) => left.sortKey - right.sortKey);
|
|
1406
1421
|
for (const object of visibleObjects) {
|
|
1407
1422
|
const direction = object.y > sceneHeight * 0.62 ? -1 : 1;
|
|
1408
1423
|
const labelHalfWidth = estimateLabelHalfWidth(object, labelMultiplier);
|
|
@@ -1422,6 +1437,7 @@ var WorldOrbit = (() => {
|
|
|
1422
1437
|
objectId: object.objectId,
|
|
1423
1438
|
object: object.object,
|
|
1424
1439
|
groupId: object.groupId,
|
|
1440
|
+
semanticGroupIds: [...object.semanticGroupIds],
|
|
1425
1441
|
label: object.label,
|
|
1426
1442
|
secondaryLabel: object.secondaryLabel,
|
|
1427
1443
|
x: object.x,
|
|
@@ -1434,7 +1450,7 @@ var WorldOrbit = (() => {
|
|
|
1434
1450
|
}
|
|
1435
1451
|
return labels;
|
|
1436
1452
|
}
|
|
1437
|
-
function createSceneLayers(orbitVisuals, leaders, objects, labels) {
|
|
1453
|
+
function createSceneLayers(orbitVisuals, relations, leaders, objects, labels) {
|
|
1438
1454
|
const backOrbitIds = orbitVisuals.filter((visual) => !visual.hidden && Boolean(visual.backArcPath)).map((visual) => visual.renderId);
|
|
1439
1455
|
const frontOrbitIds = orbitVisuals.filter((visual) => !visual.hidden).map((visual) => visual.renderId);
|
|
1440
1456
|
return [
|
|
@@ -1445,6 +1461,10 @@ var WorldOrbit = (() => {
|
|
|
1445
1461
|
},
|
|
1446
1462
|
{ id: "orbits-back", renderIds: backOrbitIds },
|
|
1447
1463
|
{ id: "orbits-front", renderIds: frontOrbitIds },
|
|
1464
|
+
{
|
|
1465
|
+
id: "relations",
|
|
1466
|
+
renderIds: relations.filter((relation) => !relation.hidden).map((relation) => relation.renderId)
|
|
1467
|
+
},
|
|
1448
1468
|
{
|
|
1449
1469
|
id: "objects",
|
|
1450
1470
|
renderIds: objects.filter((object) => !object.hidden).map((object) => object.renderId)
|
|
@@ -1509,6 +1529,36 @@ var WorldOrbit = (() => {
|
|
|
1509
1529
|
}
|
|
1510
1530
|
return [...groups.values()].sort((left, right) => left.label.localeCompare(right.label));
|
|
1511
1531
|
}
|
|
1532
|
+
function createSceneSemanticGroups(document2, objects) {
|
|
1533
|
+
return [...document2.groups].map((group) => ({
|
|
1534
|
+
id: group.id,
|
|
1535
|
+
label: group.label,
|
|
1536
|
+
summary: group.summary,
|
|
1537
|
+
color: group.color,
|
|
1538
|
+
tags: [...group.tags],
|
|
1539
|
+
hidden: group.hidden,
|
|
1540
|
+
objectIds: objects.filter((object) => !object.hidden && object.semanticGroupIds.includes(group.id)).map((object) => object.objectId)
|
|
1541
|
+
})).sort((left, right) => left.label.localeCompare(right.label));
|
|
1542
|
+
}
|
|
1543
|
+
function createSceneRelations(document2, objects) {
|
|
1544
|
+
const objectMap = new Map(objects.map((object) => [object.objectId, object]));
|
|
1545
|
+
return document2.relations.map((relation) => {
|
|
1546
|
+
const from = objectMap.get(relation.from);
|
|
1547
|
+
const to = objectMap.get(relation.to);
|
|
1548
|
+
return {
|
|
1549
|
+
renderId: `${createRenderId(relation.id)}-relation`,
|
|
1550
|
+
relationId: relation.id,
|
|
1551
|
+
relation,
|
|
1552
|
+
fromObjectId: relation.from,
|
|
1553
|
+
toObjectId: relation.to,
|
|
1554
|
+
x1: from?.x ?? 0,
|
|
1555
|
+
y1: from?.y ?? 0,
|
|
1556
|
+
x2: to?.x ?? 0,
|
|
1557
|
+
y2: to?.y ?? 0,
|
|
1558
|
+
hidden: relation.hidden || !from || !to || from.hidden || to.hidden
|
|
1559
|
+
};
|
|
1560
|
+
}).sort((left, right) => left.relation.id.localeCompare(right.relation.id));
|
|
1561
|
+
}
|
|
1512
1562
|
function createSceneViewpoints(document2, projection, preset, relationships, objectMap) {
|
|
1513
1563
|
const generatedOverview = createGeneratedOverviewViewpoint(document2, projection, preset);
|
|
1514
1564
|
const drafts = /* @__PURE__ */ new Map();
|
|
@@ -1526,7 +1576,7 @@ var WorldOrbit = (() => {
|
|
|
1526
1576
|
}
|
|
1527
1577
|
const field = fieldParts.join(".").toLowerCase();
|
|
1528
1578
|
const draft = drafts.get(id) ?? { id };
|
|
1529
|
-
applyViewpointField(draft, field, value, projection, preset, relationships, objectMap);
|
|
1579
|
+
applyViewpointField(draft, field, value, document2, projection, preset, relationships, objectMap);
|
|
1530
1580
|
drafts.set(id, draft);
|
|
1531
1581
|
}
|
|
1532
1582
|
const viewpoints = [...drafts.values()].map((draft) => finalizeViewpointDraft(draft, projection, preset, objectMap)).filter(Boolean);
|
|
@@ -1554,7 +1604,8 @@ var WorldOrbit = (() => {
|
|
|
1554
1604
|
});
|
|
1555
1605
|
}
|
|
1556
1606
|
function createGeneratedOverviewViewpoint(document2, projection, preset) {
|
|
1557
|
-
const
|
|
1607
|
+
const title = document2.system?.title ?? document2.system?.properties.title;
|
|
1608
|
+
const label = title ? `${String(title)} Overview` : "Overview";
|
|
1558
1609
|
return {
|
|
1559
1610
|
id: "overview",
|
|
1560
1611
|
label,
|
|
@@ -1570,7 +1621,7 @@ var WorldOrbit = (() => {
|
|
|
1570
1621
|
generated: true
|
|
1571
1622
|
};
|
|
1572
1623
|
}
|
|
1573
|
-
function applyViewpointField(draft, field, value, projection, preset, relationships, objectMap) {
|
|
1624
|
+
function applyViewpointField(draft, field, value, document2, projection, preset, relationships, objectMap) {
|
|
1574
1625
|
const normalizedValue = value.trim();
|
|
1575
1626
|
switch (field) {
|
|
1576
1627
|
case "label":
|
|
@@ -1637,7 +1688,7 @@ var WorldOrbit = (() => {
|
|
|
1637
1688
|
case "groups":
|
|
1638
1689
|
draft.filter = {
|
|
1639
1690
|
...draft.filter ?? createEmptyViewpointFilter(),
|
|
1640
|
-
groupIds: parseViewpointGroups(normalizedValue, relationships, objectMap)
|
|
1691
|
+
groupIds: parseViewpointGroups(normalizedValue, document2, relationships, objectMap)
|
|
1641
1692
|
};
|
|
1642
1693
|
return;
|
|
1643
1694
|
}
|
|
@@ -1710,7 +1761,7 @@ var WorldOrbit = (() => {
|
|
|
1710
1761
|
next["orbits-front"] = enabled;
|
|
1711
1762
|
continue;
|
|
1712
1763
|
}
|
|
1713
|
-
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
1764
|
+
if (rawLayer === "background" || rawLayer === "guides" || rawLayer === "orbits-back" || rawLayer === "orbits-front" || rawLayer === "relations" || rawLayer === "objects" || rawLayer === "labels" || rawLayer === "metadata") {
|
|
1714
1765
|
next[rawLayer] = enabled;
|
|
1715
1766
|
}
|
|
1716
1767
|
}
|
|
@@ -1719,8 +1770,11 @@ var WorldOrbit = (() => {
|
|
|
1719
1770
|
function parseViewpointObjectTypes(value) {
|
|
1720
1771
|
return splitListValue(value).filter((entry) => entry === "star" || entry === "planet" || entry === "moon" || entry === "belt" || entry === "asteroid" || entry === "comet" || entry === "ring" || entry === "structure" || entry === "phenomenon");
|
|
1721
1772
|
}
|
|
1722
|
-
function parseViewpointGroups(value, relationships, objectMap) {
|
|
1773
|
+
function parseViewpointGroups(value, document2, relationships, objectMap) {
|
|
1723
1774
|
return splitListValue(value).map((entry) => {
|
|
1775
|
+
if (document2.schemaVersion === "2.1" || document2.groups.some((group) => group.id === entry)) {
|
|
1776
|
+
return entry;
|
|
1777
|
+
}
|
|
1724
1778
|
if (entry.startsWith("wo-") && entry.endsWith("-group")) {
|
|
1725
1779
|
return entry;
|
|
1726
1780
|
}
|
|
@@ -2504,8 +2558,11 @@ var WorldOrbit = (() => {
|
|
|
2504
2558
|
return {
|
|
2505
2559
|
format: "worldorbit",
|
|
2506
2560
|
version: "2.0",
|
|
2561
|
+
schemaVersion: "2.0",
|
|
2507
2562
|
sourceVersion: document2.version,
|
|
2508
2563
|
system,
|
|
2564
|
+
groups: structuredClone(document2.groups ?? []),
|
|
2565
|
+
relations: structuredClone(document2.relations ?? []),
|
|
2509
2566
|
objects: document2.objects.map(cloneWorldOrbitObject),
|
|
2510
2567
|
diagnostics
|
|
2511
2568
|
};
|
|
@@ -2517,13 +2574,20 @@ var WorldOrbit = (() => {
|
|
|
2517
2574
|
const system = document2.system ? {
|
|
2518
2575
|
type: "system",
|
|
2519
2576
|
id: document2.system.id,
|
|
2577
|
+
title: document2.system.title,
|
|
2578
|
+
description: document2.system.description,
|
|
2579
|
+
epoch: document2.system.epoch,
|
|
2580
|
+
referencePlane: document2.system.referencePlane,
|
|
2520
2581
|
properties: materializeDraftSystemProperties(document2.system),
|
|
2521
2582
|
info: materializeDraftSystemInfo(document2.system)
|
|
2522
2583
|
} : null;
|
|
2523
2584
|
return {
|
|
2524
2585
|
format: "worldorbit",
|
|
2525
2586
|
version: "1.0",
|
|
2587
|
+
schemaVersion: document2.version,
|
|
2526
2588
|
system,
|
|
2589
|
+
groups: structuredClone(document2.groups ?? []),
|
|
2590
|
+
relations: structuredClone(document2.relations ?? []),
|
|
2527
2591
|
objects: document2.objects.map(cloneWorldOrbitObject)
|
|
2528
2592
|
};
|
|
2529
2593
|
}
|
|
@@ -2538,7 +2602,10 @@ var WorldOrbit = (() => {
|
|
|
2538
2602
|
return {
|
|
2539
2603
|
type: "system",
|
|
2540
2604
|
id: document2.system?.id ?? "WorldOrbit",
|
|
2541
|
-
title: typeof document2.system?.properties.title === "string" ? document2.system.properties.title : null,
|
|
2605
|
+
title: document2.system?.title ?? (typeof document2.system?.properties.title === "string" ? document2.system.properties.title : null),
|
|
2606
|
+
description: document2.system?.description ?? null,
|
|
2607
|
+
epoch: document2.system?.epoch ?? null,
|
|
2608
|
+
referencePlane: document2.system?.referencePlane ?? null,
|
|
2542
2609
|
defaults,
|
|
2543
2610
|
atlasMetadata,
|
|
2544
2611
|
viewpoints: scene.viewpoints.map(mapSceneViewpointToDraftViewpoint),
|
|
@@ -2665,6 +2732,17 @@ var WorldOrbit = (() => {
|
|
|
2665
2732
|
function cloneWorldOrbitObject(object) {
|
|
2666
2733
|
return {
|
|
2667
2734
|
...object,
|
|
2735
|
+
groups: object.groups ? [...object.groups] : void 0,
|
|
2736
|
+
resonance: object.resonance ? { ...object.resonance } : object.resonance,
|
|
2737
|
+
renderHints: object.renderHints ? { ...object.renderHints } : object.renderHints,
|
|
2738
|
+
deriveRules: object.deriveRules ? object.deriveRules.map((rule) => ({ ...rule })) : void 0,
|
|
2739
|
+
validationRules: object.validationRules ? object.validationRules.map((rule) => ({ ...rule })) : void 0,
|
|
2740
|
+
lockedFields: object.lockedFields ? [...object.lockedFields] : void 0,
|
|
2741
|
+
tolerances: object.tolerances ? object.tolerances.map((entry) => ({
|
|
2742
|
+
field: entry.field,
|
|
2743
|
+
value: entry.value && typeof entry.value === "object" && "value" in entry.value ? { value: entry.value.value, unit: entry.value.unit } : Array.isArray(entry.value) ? [...entry.value] : entry.value
|
|
2744
|
+
})) : void 0,
|
|
2745
|
+
typedBlocks: object.typedBlocks ? Object.fromEntries(Object.entries(object.typedBlocks).map(([key, block]) => [key, { ...block ?? {} }])) : void 0,
|
|
2668
2746
|
properties: cloneProperties(object.properties),
|
|
2669
2747
|
placement: object.placement ? structuredClone(object.placement) : null,
|
|
2670
2748
|
info: { ...object.info }
|
|
@@ -2709,71 +2787,80 @@ var WorldOrbit = (() => {
|
|
|
2709
2787
|
if (system.defaults.units) {
|
|
2710
2788
|
properties.units = system.defaults.units;
|
|
2711
2789
|
}
|
|
2790
|
+
if (system.description) {
|
|
2791
|
+
properties.description = system.description;
|
|
2792
|
+
}
|
|
2793
|
+
if (system.epoch) {
|
|
2794
|
+
properties.epoch = system.epoch;
|
|
2795
|
+
}
|
|
2796
|
+
if (system.referencePlane) {
|
|
2797
|
+
properties.referencePlane = system.referencePlane;
|
|
2798
|
+
}
|
|
2712
2799
|
return properties;
|
|
2713
2800
|
}
|
|
2714
2801
|
function materializeDraftSystemInfo(system) {
|
|
2715
|
-
const
|
|
2802
|
+
const info2 = {
|
|
2716
2803
|
...system.atlasMetadata
|
|
2717
2804
|
};
|
|
2718
2805
|
if (system.defaults.theme) {
|
|
2719
|
-
|
|
2806
|
+
info2["atlas.theme"] = system.defaults.theme;
|
|
2720
2807
|
}
|
|
2721
2808
|
for (const viewpoint of system.viewpoints) {
|
|
2722
2809
|
const prefix = `viewpoint.${viewpoint.id}`;
|
|
2723
|
-
|
|
2810
|
+
info2[`${prefix}.label`] = viewpoint.label;
|
|
2724
2811
|
if (viewpoint.summary) {
|
|
2725
|
-
|
|
2812
|
+
info2[`${prefix}.summary`] = viewpoint.summary;
|
|
2726
2813
|
}
|
|
2727
2814
|
if (viewpoint.focusObjectId) {
|
|
2728
|
-
|
|
2815
|
+
info2[`${prefix}.focus`] = viewpoint.focusObjectId;
|
|
2729
2816
|
}
|
|
2730
2817
|
if (viewpoint.selectedObjectId) {
|
|
2731
|
-
|
|
2818
|
+
info2[`${prefix}.select`] = viewpoint.selectedObjectId;
|
|
2732
2819
|
}
|
|
2733
2820
|
if (viewpoint.projection) {
|
|
2734
|
-
|
|
2821
|
+
info2[`${prefix}.projection`] = viewpoint.projection;
|
|
2735
2822
|
}
|
|
2736
2823
|
if (viewpoint.preset) {
|
|
2737
|
-
|
|
2824
|
+
info2[`${prefix}.preset`] = viewpoint.preset;
|
|
2738
2825
|
}
|
|
2739
2826
|
if (viewpoint.zoom !== null) {
|
|
2740
|
-
|
|
2827
|
+
info2[`${prefix}.zoom`] = String(viewpoint.zoom);
|
|
2741
2828
|
}
|
|
2742
2829
|
if (viewpoint.rotationDeg !== 0) {
|
|
2743
|
-
|
|
2830
|
+
info2[`${prefix}.rotation`] = String(viewpoint.rotationDeg);
|
|
2744
2831
|
}
|
|
2745
2832
|
const serializedLayers = serializeViewpointLayers(viewpoint.layers);
|
|
2746
2833
|
if (serializedLayers) {
|
|
2747
|
-
|
|
2834
|
+
info2[`${prefix}.layers`] = serializedLayers;
|
|
2748
2835
|
}
|
|
2749
2836
|
if (viewpoint.filter?.query) {
|
|
2750
|
-
|
|
2837
|
+
info2[`${prefix}.query`] = viewpoint.filter.query;
|
|
2751
2838
|
}
|
|
2752
2839
|
if ((viewpoint.filter?.objectTypes.length ?? 0) > 0) {
|
|
2753
|
-
|
|
2840
|
+
info2[`${prefix}.types`] = viewpoint.filter?.objectTypes.join(" ") ?? "";
|
|
2754
2841
|
}
|
|
2755
2842
|
if ((viewpoint.filter?.tags.length ?? 0) > 0) {
|
|
2756
|
-
|
|
2843
|
+
info2[`${prefix}.tags`] = viewpoint.filter?.tags.join(" ") ?? "";
|
|
2757
2844
|
}
|
|
2758
2845
|
if ((viewpoint.filter?.groupIds.length ?? 0) > 0) {
|
|
2759
|
-
|
|
2846
|
+
info2[`${prefix}.groups`] = viewpoint.filter?.groupIds.join(" ") ?? "";
|
|
2760
2847
|
}
|
|
2761
2848
|
}
|
|
2762
2849
|
for (const annotation of system.annotations) {
|
|
2763
2850
|
const prefix = `annotation.${annotation.id}`;
|
|
2764
|
-
|
|
2851
|
+
info2[`${prefix}.label`] = annotation.label;
|
|
2765
2852
|
if (annotation.targetObjectId) {
|
|
2766
|
-
|
|
2853
|
+
info2[`${prefix}.target`] = annotation.targetObjectId;
|
|
2767
2854
|
}
|
|
2768
|
-
|
|
2855
|
+
info2[`${prefix}.body`] = annotation.body;
|
|
2769
2856
|
if (annotation.tags.length > 0) {
|
|
2770
|
-
|
|
2857
|
+
info2[`${prefix}.tags`] = annotation.tags.join(" ");
|
|
2771
2858
|
}
|
|
2772
2859
|
if (annotation.sourceObjectId) {
|
|
2773
|
-
|
|
2860
|
+
info2[`${prefix}.source`] = annotation.sourceObjectId;
|
|
2774
2861
|
}
|
|
2775
2862
|
}
|
|
2776
|
-
return
|
|
2863
|
+
return info2;
|
|
2777
2864
|
}
|
|
2778
2865
|
function serializeViewpointLayers(layers) {
|
|
2779
2866
|
const tokens = [];
|
|
@@ -2782,7 +2869,7 @@ var WorldOrbit = (() => {
|
|
|
2782
2869
|
if (orbitFront !== void 0 || orbitBack !== void 0) {
|
|
2783
2870
|
tokens.push(orbitFront !== false || orbitBack !== false ? "orbits" : "-orbits");
|
|
2784
2871
|
}
|
|
2785
|
-
for (const key of ["background", "guides", "objects", "labels", "metadata"]) {
|
|
2872
|
+
for (const key of ["background", "guides", "relations", "objects", "labels", "metadata"]) {
|
|
2786
2873
|
if (layers[key] !== void 0) {
|
|
2787
2874
|
tokens.push(layers[key] ? key : `-${key}`);
|
|
2788
2875
|
}
|
|
@@ -2792,7 +2879,8 @@ var WorldOrbit = (() => {
|
|
|
2792
2879
|
function convertAtlasDocumentToLegacyDraft(document2) {
|
|
2793
2880
|
return {
|
|
2794
2881
|
...document2,
|
|
2795
|
-
version: "2.0-draft"
|
|
2882
|
+
version: "2.0-draft",
|
|
2883
|
+
schemaVersion: "2.0-draft"
|
|
2796
2884
|
};
|
|
2797
2885
|
}
|
|
2798
2886
|
|
|
@@ -2834,19 +2922,28 @@ var WorldOrbit = (() => {
|
|
|
2834
2922
|
];
|
|
2835
2923
|
function formatDocument(document2, options = {}) {
|
|
2836
2924
|
const schema = options.schema ?? "auto";
|
|
2837
|
-
const useDraft = schema === "2.0" || schema === "2.0-draft" || document2.version === "2.0" || document2.version === "2.0-draft";
|
|
2925
|
+
const useDraft = schema === "2.0" || schema === "2.1" || schema === "2.0-draft" || document2.version === "2.0" || document2.version === "2.1" || document2.version === "2.0-draft";
|
|
2838
2926
|
if (useDraft) {
|
|
2839
2927
|
if (schema === "2.0-draft") {
|
|
2840
|
-
const legacyDraftDocument = document2.version === "2.0-draft" ? document2 : document2.version === "2.0" ? {
|
|
2928
|
+
const legacyDraftDocument = document2.version === "2.0-draft" ? document2 : document2.version === "2.0" || document2.version === "2.1" ? {
|
|
2841
2929
|
...document2,
|
|
2842
|
-
version: "2.0-draft"
|
|
2930
|
+
version: "2.0-draft",
|
|
2931
|
+
schemaVersion: "2.0-draft"
|
|
2843
2932
|
} : upgradeDocumentToDraftV2(document2);
|
|
2844
2933
|
return formatDraftDocument(legacyDraftDocument);
|
|
2845
2934
|
}
|
|
2846
|
-
const atlasDocument = document2.version === "2.0" ? document2 : document2.version === "2.0-draft" ? {
|
|
2935
|
+
const atlasDocument = document2.version === "2.0" || document2.version === "2.1" ? document2 : document2.version === "2.0-draft" ? {
|
|
2847
2936
|
...document2,
|
|
2848
|
-
version: "2.0"
|
|
2937
|
+
version: "2.0",
|
|
2938
|
+
schemaVersion: "2.0"
|
|
2849
2939
|
} : upgradeDocumentToV2(document2);
|
|
2940
|
+
if (schema === "2.1" && atlasDocument.version !== "2.1") {
|
|
2941
|
+
return formatAtlasDocument({
|
|
2942
|
+
...atlasDocument,
|
|
2943
|
+
version: "2.1",
|
|
2944
|
+
schemaVersion: "2.1"
|
|
2945
|
+
});
|
|
2946
|
+
}
|
|
2850
2947
|
return formatAtlasDocument(atlasDocument);
|
|
2851
2948
|
}
|
|
2852
2949
|
const lines = [];
|
|
@@ -2864,10 +2961,18 @@ var WorldOrbit = (() => {
|
|
|
2864
2961
|
return lines.join("\n");
|
|
2865
2962
|
}
|
|
2866
2963
|
function formatAtlasDocument(document2) {
|
|
2867
|
-
const lines = [
|
|
2964
|
+
const lines = [`schema ${document2.version}`, ""];
|
|
2868
2965
|
if (document2.system) {
|
|
2869
2966
|
lines.push(...formatAtlasSystem(document2.system));
|
|
2870
2967
|
}
|
|
2968
|
+
for (const group of [...document2.groups].sort(compareIdLike)) {
|
|
2969
|
+
lines.push("");
|
|
2970
|
+
lines.push(...formatAtlasGroup(group));
|
|
2971
|
+
}
|
|
2972
|
+
for (const relation of [...document2.relations].sort(compareIdLike)) {
|
|
2973
|
+
lines.push("");
|
|
2974
|
+
lines.push(...formatAtlasRelation(relation));
|
|
2975
|
+
}
|
|
2871
2976
|
const sortedObjects = [...document2.objects].sort(compareObjects);
|
|
2872
2977
|
if (sortedObjects.length > 0 && lines.at(-1) !== "") {
|
|
2873
2978
|
lines.push("");
|
|
@@ -2883,12 +2988,21 @@ var WorldOrbit = (() => {
|
|
|
2883
2988
|
function formatDraftDocument(document2) {
|
|
2884
2989
|
const legacy = document2.version === "2.0-draft" ? document2 : {
|
|
2885
2990
|
...document2,
|
|
2886
|
-
version: "2.0-draft"
|
|
2991
|
+
version: "2.0-draft",
|
|
2992
|
+
schemaVersion: "2.0-draft"
|
|
2887
2993
|
};
|
|
2888
2994
|
const lines = ["schema 2.0-draft", ""];
|
|
2889
2995
|
if (legacy.system) {
|
|
2890
2996
|
lines.push(...formatAtlasSystem(legacy.system));
|
|
2891
2997
|
}
|
|
2998
|
+
for (const group of [...legacy.groups].sort(compareIdLike)) {
|
|
2999
|
+
lines.push("");
|
|
3000
|
+
lines.push(...formatAtlasGroup(group));
|
|
3001
|
+
}
|
|
3002
|
+
for (const relation of [...legacy.relations].sort(compareIdLike)) {
|
|
3003
|
+
lines.push("");
|
|
3004
|
+
lines.push(...formatAtlasRelation(relation));
|
|
3005
|
+
}
|
|
2892
3006
|
const sortedObjects = [...legacy.objects].sort(compareObjects);
|
|
2893
3007
|
if (sortedObjects.length > 0 && lines.at(-1) !== "") {
|
|
2894
3008
|
lines.push("");
|
|
@@ -2904,11 +3018,38 @@ var WorldOrbit = (() => {
|
|
|
2904
3018
|
function formatSystem(system) {
|
|
2905
3019
|
return formatLines("system", system.id, system.properties, null, system.info);
|
|
2906
3020
|
}
|
|
3021
|
+
function formatLines(objectType, id, properties, placement, info2) {
|
|
3022
|
+
const lines = [`${objectType} ${id}`];
|
|
3023
|
+
const fieldLines = [...formatPlacement(placement), ...formatProperties(properties)];
|
|
3024
|
+
for (const fieldLine of fieldLines) {
|
|
3025
|
+
lines.push(` ${fieldLine}`);
|
|
3026
|
+
}
|
|
3027
|
+
const infoEntries = Object.entries(info2).sort(([left], [right]) => left.localeCompare(right));
|
|
3028
|
+
if (infoEntries.length > 0) {
|
|
3029
|
+
if (fieldLines.length > 0) {
|
|
3030
|
+
lines.push("");
|
|
3031
|
+
}
|
|
3032
|
+
lines.push(" info");
|
|
3033
|
+
for (const [key, value] of infoEntries) {
|
|
3034
|
+
lines.push(` ${key} ${quoteIfNeeded(value)}`);
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
return lines;
|
|
3038
|
+
}
|
|
2907
3039
|
function formatAtlasSystem(system) {
|
|
2908
3040
|
const lines = [`system ${system.id}`];
|
|
2909
3041
|
if (system.title) {
|
|
2910
3042
|
lines.push(` title ${quoteIfNeeded(system.title)}`);
|
|
2911
3043
|
}
|
|
3044
|
+
if (system.description) {
|
|
3045
|
+
lines.push(` description ${quoteIfNeeded(system.description)}`);
|
|
3046
|
+
}
|
|
3047
|
+
if (system.epoch) {
|
|
3048
|
+
lines.push(` epoch ${quoteIfNeeded(system.epoch)}`);
|
|
3049
|
+
}
|
|
3050
|
+
if (system.referencePlane) {
|
|
3051
|
+
lines.push(` referencePlane ${quoteIfNeeded(system.referencePlane)}`);
|
|
3052
|
+
}
|
|
2912
3053
|
lines.push("");
|
|
2913
3054
|
lines.push("defaults");
|
|
2914
3055
|
lines.push(` view ${system.defaults.view}`);
|
|
@@ -2943,18 +3084,22 @@ var WorldOrbit = (() => {
|
|
|
2943
3084
|
return lines;
|
|
2944
3085
|
}
|
|
2945
3086
|
function formatObject(object) {
|
|
2946
|
-
return
|
|
3087
|
+
return formatWorldOrbitObject(object.type, object.id, object);
|
|
2947
3088
|
}
|
|
2948
3089
|
function formatAtlasObject(object) {
|
|
2949
|
-
return
|
|
3090
|
+
return formatWorldOrbitObject(`object ${object.type}`, object.id, object);
|
|
2950
3091
|
}
|
|
2951
|
-
function
|
|
3092
|
+
function formatWorldOrbitObject(objectType, id, object) {
|
|
2952
3093
|
const lines = [`${objectType} ${id}`];
|
|
2953
|
-
const fieldLines = [
|
|
3094
|
+
const fieldLines = [
|
|
3095
|
+
...formatPlacement(object.placement),
|
|
3096
|
+
...formatProperties(object.properties),
|
|
3097
|
+
...formatObjectMetadata(object)
|
|
3098
|
+
];
|
|
2954
3099
|
for (const fieldLine of fieldLines) {
|
|
2955
3100
|
lines.push(` ${fieldLine}`);
|
|
2956
3101
|
}
|
|
2957
|
-
const infoEntries = Object.entries(info).sort(([left], [right]) => left.localeCompare(right));
|
|
3102
|
+
const infoEntries = Object.entries(object.info).sort(([left], [right]) => left.localeCompare(right));
|
|
2958
3103
|
if (infoEntries.length > 0) {
|
|
2959
3104
|
if (fieldLines.length > 0) {
|
|
2960
3105
|
lines.push("");
|
|
@@ -2964,6 +3109,16 @@ var WorldOrbit = (() => {
|
|
|
2964
3109
|
lines.push(` ${key} ${quoteIfNeeded(value)}`);
|
|
2965
3110
|
}
|
|
2966
3111
|
}
|
|
3112
|
+
for (const blockName of ["climate", "habitability", "settlement"]) {
|
|
3113
|
+
const blockEntries = Object.entries(object.typedBlocks?.[blockName] ?? {}).sort(([left], [right]) => left.localeCompare(right));
|
|
3114
|
+
if (blockEntries.length > 0) {
|
|
3115
|
+
lines.push("");
|
|
3116
|
+
lines.push(` ${blockName}`);
|
|
3117
|
+
for (const [key, value] of blockEntries) {
|
|
3118
|
+
lines.push(` ${key} ${quoteIfNeeded(value)}`);
|
|
3119
|
+
}
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
2967
3122
|
return lines;
|
|
2968
3123
|
}
|
|
2969
3124
|
function formatPlacement(placement) {
|
|
@@ -2992,6 +3147,46 @@ var WorldOrbit = (() => {
|
|
|
2992
3147
|
function formatProperties(properties) {
|
|
2993
3148
|
return Object.keys(properties).sort(compareFieldKeys).map((key) => `${key} ${formatValue(properties[key])}`);
|
|
2994
3149
|
}
|
|
3150
|
+
function formatObjectMetadata(object) {
|
|
3151
|
+
const lines = [];
|
|
3152
|
+
if (object.groups?.length) {
|
|
3153
|
+
lines.push(`groups ${object.groups.join(" ")}`);
|
|
3154
|
+
}
|
|
3155
|
+
if (object.epoch) {
|
|
3156
|
+
lines.push(`epoch ${quoteIfNeeded(object.epoch)}`);
|
|
3157
|
+
}
|
|
3158
|
+
if (object.referencePlane) {
|
|
3159
|
+
lines.push(`referencePlane ${quoteIfNeeded(object.referencePlane)}`);
|
|
3160
|
+
}
|
|
3161
|
+
if (object.tidalLock !== void 0) {
|
|
3162
|
+
lines.push(`tidalLock ${object.tidalLock ? "true" : "false"}`);
|
|
3163
|
+
}
|
|
3164
|
+
if (object.renderHints?.renderLabel !== void 0) {
|
|
3165
|
+
lines.push(`renderLabel ${object.renderHints.renderLabel ? "true" : "false"}`);
|
|
3166
|
+
}
|
|
3167
|
+
if (object.renderHints?.renderOrbit !== void 0) {
|
|
3168
|
+
lines.push(`renderOrbit ${object.renderHints.renderOrbit ? "true" : "false"}`);
|
|
3169
|
+
}
|
|
3170
|
+
if (object.renderHints?.renderPriority !== void 0) {
|
|
3171
|
+
lines.push(`renderPriority ${object.renderHints.renderPriority}`);
|
|
3172
|
+
}
|
|
3173
|
+
if (object.resonance) {
|
|
3174
|
+
lines.push(`resonance ${object.resonance.targetObjectId} ${object.resonance.ratio}`);
|
|
3175
|
+
}
|
|
3176
|
+
for (const rule of object.deriveRules ?? []) {
|
|
3177
|
+
lines.push(`derive ${rule.field} ${rule.strategy}`);
|
|
3178
|
+
}
|
|
3179
|
+
for (const rule of object.validationRules ?? []) {
|
|
3180
|
+
lines.push(`validate ${rule.rule}`);
|
|
3181
|
+
}
|
|
3182
|
+
if (object.lockedFields?.length) {
|
|
3183
|
+
lines.push(`locked ${object.lockedFields.join(" ")}`);
|
|
3184
|
+
}
|
|
3185
|
+
for (const tolerance of object.tolerances ?? []) {
|
|
3186
|
+
lines.push(`tolerance ${tolerance.field} ${formatValue(tolerance.value)}`);
|
|
3187
|
+
}
|
|
3188
|
+
return lines;
|
|
3189
|
+
}
|
|
2995
3190
|
function formatAtlasViewpoint(viewpoint) {
|
|
2996
3191
|
const lines = [`viewpoint ${viewpoint.id}`, ` label ${quoteIfNeeded(viewpoint.label)}`];
|
|
2997
3192
|
if (viewpoint.focusObjectId) {
|
|
@@ -3047,6 +3242,50 @@ var WorldOrbit = (() => {
|
|
|
3047
3242
|
}
|
|
3048
3243
|
return lines;
|
|
3049
3244
|
}
|
|
3245
|
+
function formatAtlasGroup(group) {
|
|
3246
|
+
const lines = [`group ${group.id}`, ` label ${quoteIfNeeded(group.label)}`];
|
|
3247
|
+
if (group.summary) {
|
|
3248
|
+
lines.push(` summary ${quoteIfNeeded(group.summary)}`);
|
|
3249
|
+
}
|
|
3250
|
+
if (group.color) {
|
|
3251
|
+
lines.push(` color ${quoteIfNeeded(group.color)}`);
|
|
3252
|
+
}
|
|
3253
|
+
if (group.tags.length > 0) {
|
|
3254
|
+
lines.push(` tags ${group.tags.map(quoteIfNeeded).join(" ")}`);
|
|
3255
|
+
}
|
|
3256
|
+
if (group.hidden) {
|
|
3257
|
+
lines.push(" hidden true");
|
|
3258
|
+
}
|
|
3259
|
+
return lines;
|
|
3260
|
+
}
|
|
3261
|
+
function formatAtlasRelation(relation) {
|
|
3262
|
+
const lines = [`relation ${relation.id}`];
|
|
3263
|
+
if (relation.from) {
|
|
3264
|
+
lines.push(` from ${quoteIfNeeded(relation.from)}`);
|
|
3265
|
+
}
|
|
3266
|
+
if (relation.to) {
|
|
3267
|
+
lines.push(` to ${quoteIfNeeded(relation.to)}`);
|
|
3268
|
+
}
|
|
3269
|
+
if (relation.kind) {
|
|
3270
|
+
lines.push(` kind ${quoteIfNeeded(relation.kind)}`);
|
|
3271
|
+
}
|
|
3272
|
+
if (relation.label) {
|
|
3273
|
+
lines.push(` label ${quoteIfNeeded(relation.label)}`);
|
|
3274
|
+
}
|
|
3275
|
+
if (relation.summary) {
|
|
3276
|
+
lines.push(` summary ${quoteIfNeeded(relation.summary)}`);
|
|
3277
|
+
}
|
|
3278
|
+
if (relation.tags.length > 0) {
|
|
3279
|
+
lines.push(` tags ${relation.tags.map(quoteIfNeeded).join(" ")}`);
|
|
3280
|
+
}
|
|
3281
|
+
if (relation.color) {
|
|
3282
|
+
lines.push(` color ${quoteIfNeeded(relation.color)}`);
|
|
3283
|
+
}
|
|
3284
|
+
if (relation.hidden) {
|
|
3285
|
+
lines.push(" hidden true");
|
|
3286
|
+
}
|
|
3287
|
+
return lines;
|
|
3288
|
+
}
|
|
3050
3289
|
function formatValue(value) {
|
|
3051
3290
|
if (Array.isArray(value)) {
|
|
3052
3291
|
return value.map((item) => quoteIfNeeded(item)).join(" ");
|
|
@@ -3088,7 +3327,7 @@ var WorldOrbit = (() => {
|
|
|
3088
3327
|
if (orbitFront !== void 0 || orbitBack !== void 0) {
|
|
3089
3328
|
tokens.push(orbitFront !== false || orbitBack !== false ? "orbits" : "-orbits");
|
|
3090
3329
|
}
|
|
3091
|
-
for (const key of ["background", "guides", "objects", "labels", "metadata"]) {
|
|
3330
|
+
for (const key of ["background", "guides", "relations", "objects", "labels", "metadata"]) {
|
|
3092
3331
|
if (layers[key] !== void 0) {
|
|
3093
3332
|
tokens.push(layers[key] ? key : `-${key}`);
|
|
3094
3333
|
}
|
|
@@ -3113,6 +3352,9 @@ var WorldOrbit = (() => {
|
|
|
3113
3352
|
return leftIndex - rightIndex;
|
|
3114
3353
|
return left.id.localeCompare(right.id);
|
|
3115
3354
|
}
|
|
3355
|
+
function compareIdLike(left, right) {
|
|
3356
|
+
return left.id.localeCompare(right.id);
|
|
3357
|
+
}
|
|
3116
3358
|
function objectTypeIndex(objectType) {
|
|
3117
3359
|
switch (objectType) {
|
|
3118
3360
|
case "star":
|
|
@@ -3142,24 +3384,533 @@ var WorldOrbit = (() => {
|
|
|
3142
3384
|
return `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
|
|
3143
3385
|
}
|
|
3144
3386
|
|
|
3387
|
+
// packages/core/dist/atlas-utils.js
|
|
3388
|
+
var UNIT_PATTERN2 = /^(-?\d+(?:\.\d+)?)(kpc|min|mj|rj|ky|my|gy|au|km|me|re|pc|ly|deg|sol|K|m|s|h|d|y)?$/;
|
|
3389
|
+
var BOOLEAN_VALUES2 = /* @__PURE__ */ new Map([
|
|
3390
|
+
["true", true],
|
|
3391
|
+
["false", false],
|
|
3392
|
+
["yes", true],
|
|
3393
|
+
["no", false]
|
|
3394
|
+
]);
|
|
3395
|
+
var URL_SCHEME_PATTERN2 = /^[A-Za-z][A-Za-z0-9+.-]*:/;
|
|
3396
|
+
function normalizeIdentifier2(value) {
|
|
3397
|
+
return value.trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
3398
|
+
}
|
|
3399
|
+
function humanizeIdentifier3(value) {
|
|
3400
|
+
return value.split(/[-_]+/).filter(Boolean).map((segment) => segment[0].toUpperCase() + segment.slice(1)).join(" ");
|
|
3401
|
+
}
|
|
3402
|
+
function parseAtlasUnitValue(input, location, fieldKey) {
|
|
3403
|
+
const match = input.match(UNIT_PATTERN2);
|
|
3404
|
+
if (!match) {
|
|
3405
|
+
throw WorldOrbitError.fromLocation(`Invalid unit value "${input}"`, location);
|
|
3406
|
+
}
|
|
3407
|
+
const unitValue = {
|
|
3408
|
+
value: Number(match[1]),
|
|
3409
|
+
unit: match[2] ?? null
|
|
3410
|
+
};
|
|
3411
|
+
if (fieldKey) {
|
|
3412
|
+
const schema = getFieldSchema(fieldKey);
|
|
3413
|
+
if (schema?.unitFamily && !unitFamilyAllowsUnit(schema.unitFamily, unitValue.unit)) {
|
|
3414
|
+
throw WorldOrbitError.fromLocation(`Unit "${unitValue.unit ?? "none"}" is not valid for "${fieldKey}"`, location);
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3417
|
+
return unitValue;
|
|
3418
|
+
}
|
|
3419
|
+
function tryParseAtlasUnitValue(input) {
|
|
3420
|
+
const match = input.match(UNIT_PATTERN2);
|
|
3421
|
+
if (!match) {
|
|
3422
|
+
return null;
|
|
3423
|
+
}
|
|
3424
|
+
return {
|
|
3425
|
+
value: Number(match[1]),
|
|
3426
|
+
unit: match[2] ?? null
|
|
3427
|
+
};
|
|
3428
|
+
}
|
|
3429
|
+
function parseAtlasNumber(input, key, location) {
|
|
3430
|
+
const value = Number(input);
|
|
3431
|
+
if (!Number.isFinite(value)) {
|
|
3432
|
+
throw WorldOrbitError.fromLocation(`Invalid numeric value "${input}" for "${key}"`, location);
|
|
3433
|
+
}
|
|
3434
|
+
return value;
|
|
3435
|
+
}
|
|
3436
|
+
function parseAtlasBoolean(input, key, location) {
|
|
3437
|
+
const parsed = BOOLEAN_VALUES2.get(input.toLowerCase());
|
|
3438
|
+
if (parsed === void 0) {
|
|
3439
|
+
throw WorldOrbitError.fromLocation(`Invalid boolean value "${input}" for "${key}"`, location);
|
|
3440
|
+
}
|
|
3441
|
+
return parsed;
|
|
3442
|
+
}
|
|
3443
|
+
function parseAtlasAtReference(target, location) {
|
|
3444
|
+
if (/^[A-Za-z0-9._-]+-[A-Za-z0-9._-]+:L\d+$/i.test(target)) {
|
|
3445
|
+
throw WorldOrbitError.fromLocation(`Invalid special position "${target}"`, location);
|
|
3446
|
+
}
|
|
3447
|
+
const pairedMatch = target.match(/^([A-Za-z0-9._-]+)-([A-Za-z0-9._-]+):(L[1-5])$/);
|
|
3448
|
+
if (pairedMatch) {
|
|
3449
|
+
return {
|
|
3450
|
+
kind: "lagrange",
|
|
3451
|
+
primary: pairedMatch[1],
|
|
3452
|
+
secondary: pairedMatch[2],
|
|
3453
|
+
point: pairedMatch[3]
|
|
3454
|
+
};
|
|
3455
|
+
}
|
|
3456
|
+
const simpleMatch = target.match(/^([A-Za-z0-9._-]+):(L[1-5])$/);
|
|
3457
|
+
if (simpleMatch) {
|
|
3458
|
+
return {
|
|
3459
|
+
kind: "lagrange",
|
|
3460
|
+
primary: simpleMatch[1],
|
|
3461
|
+
secondary: null,
|
|
3462
|
+
point: simpleMatch[2]
|
|
3463
|
+
};
|
|
3464
|
+
}
|
|
3465
|
+
if (/^[A-Za-z0-9._-]+:L\d+$/i.test(target)) {
|
|
3466
|
+
throw WorldOrbitError.fromLocation(`Invalid special position "${target}"`, location);
|
|
3467
|
+
}
|
|
3468
|
+
const anchorMatch = target.match(/^([A-Za-z0-9._-]+):([A-Za-z0-9._-]+)$/);
|
|
3469
|
+
if (anchorMatch) {
|
|
3470
|
+
return {
|
|
3471
|
+
kind: "anchor",
|
|
3472
|
+
objectId: anchorMatch[1],
|
|
3473
|
+
anchor: anchorMatch[2]
|
|
3474
|
+
};
|
|
3475
|
+
}
|
|
3476
|
+
return {
|
|
3477
|
+
kind: "named",
|
|
3478
|
+
name: target
|
|
3479
|
+
};
|
|
3480
|
+
}
|
|
3481
|
+
function validateAtlasImageSource(value, location) {
|
|
3482
|
+
if (!value) {
|
|
3483
|
+
throw WorldOrbitError.fromLocation('Field "image" must not be empty', location);
|
|
3484
|
+
}
|
|
3485
|
+
if (value.startsWith("//")) {
|
|
3486
|
+
throw WorldOrbitError.fromLocation('Field "image" must use a relative path, root-relative path, or an http/https URL', location);
|
|
3487
|
+
}
|
|
3488
|
+
const schemeMatch = value.match(URL_SCHEME_PATTERN2);
|
|
3489
|
+
if (!schemeMatch) {
|
|
3490
|
+
return;
|
|
3491
|
+
}
|
|
3492
|
+
const scheme = schemeMatch[0].slice(0, -1).toLowerCase();
|
|
3493
|
+
if (scheme !== "http" && scheme !== "https") {
|
|
3494
|
+
throw WorldOrbitError.fromLocation(`Field "image" does not support the "${scheme}" scheme`, location);
|
|
3495
|
+
}
|
|
3496
|
+
}
|
|
3497
|
+
function normalizeLegacyScalarValue(key, values, location) {
|
|
3498
|
+
const schema = getFieldSchema(key);
|
|
3499
|
+
if (!schema) {
|
|
3500
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${key}"`, location);
|
|
3501
|
+
}
|
|
3502
|
+
if (schema.arity === "single" && values.length !== 1) {
|
|
3503
|
+
throw WorldOrbitError.fromLocation(`Field "${key}" expects exactly one value`, location);
|
|
3504
|
+
}
|
|
3505
|
+
switch (schema.kind) {
|
|
3506
|
+
case "list":
|
|
3507
|
+
return values;
|
|
3508
|
+
case "boolean":
|
|
3509
|
+
return parseAtlasBoolean(singleAtlasValue(values, key, location), key, location);
|
|
3510
|
+
case "number":
|
|
3511
|
+
return parseAtlasNumber(singleAtlasValue(values, key, location), key, location);
|
|
3512
|
+
case "unit":
|
|
3513
|
+
return parseAtlasUnitValue(singleAtlasValue(values, key, location), location, key);
|
|
3514
|
+
case "string": {
|
|
3515
|
+
const value = values.join(" ").trim();
|
|
3516
|
+
if (key === "image") {
|
|
3517
|
+
validateAtlasImageSource(value, location);
|
|
3518
|
+
}
|
|
3519
|
+
return value;
|
|
3520
|
+
}
|
|
3521
|
+
}
|
|
3522
|
+
}
|
|
3523
|
+
function ensureAtlasFieldSupported(key, objectType, location) {
|
|
3524
|
+
const schema = getFieldSchema(key);
|
|
3525
|
+
if (!schema) {
|
|
3526
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${key}"`, location);
|
|
3527
|
+
}
|
|
3528
|
+
if (!schema.objectTypes.includes(objectType)) {
|
|
3529
|
+
throw WorldOrbitError.fromLocation(`Field "${key}" is not valid on "${objectType}"`, location);
|
|
3530
|
+
}
|
|
3531
|
+
}
|
|
3532
|
+
function singleAtlasValue(values, key, location) {
|
|
3533
|
+
if (values.length !== 1) {
|
|
3534
|
+
throw WorldOrbitError.fromLocation(`Field "${key}" expects exactly one value`, location);
|
|
3535
|
+
}
|
|
3536
|
+
return values[0];
|
|
3537
|
+
}
|
|
3538
|
+
|
|
3539
|
+
// packages/core/dist/atlas-validate.js
|
|
3540
|
+
var SURFACE_TARGET_TYPES2 = /* @__PURE__ */ new Set(["star", "planet", "moon", "asteroid", "comet"]);
|
|
3541
|
+
var EARTH_MASSES_PER_SOLAR = 332946.0487;
|
|
3542
|
+
var JUPITER_MASSES_PER_SOLAR = 1047.3486;
|
|
3543
|
+
var AU_IN_KM2 = 1495978707e-1;
|
|
3544
|
+
var EARTH_RADIUS_IN_KM2 = 6371;
|
|
3545
|
+
var SOLAR_RADIUS_IN_KM2 = 695700;
|
|
3546
|
+
var LY_IN_AU2 = 63241.077;
|
|
3547
|
+
var PC_IN_AU2 = 206264.806;
|
|
3548
|
+
var KPC_IN_AU2 = 206264806;
|
|
3549
|
+
function collectAtlasDiagnostics(document2, sourceSchemaVersion) {
|
|
3550
|
+
const diagnostics = [];
|
|
3551
|
+
const objectMap = new Map(document2.objects.map((object) => [object.id, object]));
|
|
3552
|
+
const groupIds = new Set(document2.groups.map((group) => group.id));
|
|
3553
|
+
if (!document2.system) {
|
|
3554
|
+
diagnostics.push(error("validate.system.required", "Atlas documents must declare exactly one system."));
|
|
3555
|
+
}
|
|
3556
|
+
const knownIds = /* @__PURE__ */ new Map();
|
|
3557
|
+
for (const [kind, ids] of [
|
|
3558
|
+
["group", document2.groups.map((group) => group.id)],
|
|
3559
|
+
["viewpoint", document2.system?.viewpoints.map((viewpoint) => viewpoint.id) ?? []],
|
|
3560
|
+
["annotation", document2.system?.annotations.map((annotation) => annotation.id) ?? []],
|
|
3561
|
+
["relation", document2.relations.map((relation) => relation.id)],
|
|
3562
|
+
["object", document2.objects.map((object) => object.id)]
|
|
3563
|
+
]) {
|
|
3564
|
+
for (const id of ids) {
|
|
3565
|
+
const previous = knownIds.get(id);
|
|
3566
|
+
if (previous) {
|
|
3567
|
+
diagnostics.push(error("validate.id.duplicate", `Duplicate ${kind} id "${id}" already used by ${previous}.`));
|
|
3568
|
+
} else {
|
|
3569
|
+
knownIds.set(id, kind);
|
|
3570
|
+
}
|
|
3571
|
+
}
|
|
3572
|
+
}
|
|
3573
|
+
for (const relation of document2.relations) {
|
|
3574
|
+
validateRelation(relation, objectMap, diagnostics);
|
|
3575
|
+
}
|
|
3576
|
+
for (const viewpoint of document2.system?.viewpoints ?? []) {
|
|
3577
|
+
validateViewpointFilter(viewpoint.filter, groupIds, sourceSchemaVersion, diagnostics, viewpoint.id);
|
|
3578
|
+
}
|
|
3579
|
+
for (const object of document2.objects) {
|
|
3580
|
+
validateObject(object, document2.system, objectMap, groupIds, diagnostics);
|
|
3581
|
+
}
|
|
3582
|
+
return diagnostics;
|
|
3583
|
+
}
|
|
3584
|
+
function validateRelation(relation, objectMap, diagnostics) {
|
|
3585
|
+
if (!relation.from) {
|
|
3586
|
+
diagnostics.push(error("validate.relation.from.required", `Relation "${relation.id}" is missing a "from" target.`));
|
|
3587
|
+
} else if (!objectMap.has(relation.from)) {
|
|
3588
|
+
diagnostics.push(error("validate.relation.from.unknown", `Unknown relation source "${relation.from}" on "${relation.id}".`));
|
|
3589
|
+
}
|
|
3590
|
+
if (!relation.to) {
|
|
3591
|
+
diagnostics.push(error("validate.relation.to.required", `Relation "${relation.id}" is missing a "to" target.`));
|
|
3592
|
+
} else if (!objectMap.has(relation.to)) {
|
|
3593
|
+
diagnostics.push(error("validate.relation.to.unknown", `Unknown relation target "${relation.to}" on "${relation.id}".`));
|
|
3594
|
+
}
|
|
3595
|
+
if (!relation.kind) {
|
|
3596
|
+
diagnostics.push(error("validate.relation.kind.required", `Relation "${relation.id}" is missing a "kind" value.`));
|
|
3597
|
+
}
|
|
3598
|
+
}
|
|
3599
|
+
function validateViewpointFilter(filter, groupIds, sourceSchemaVersion, diagnostics, viewpointId) {
|
|
3600
|
+
if (!filter || sourceSchemaVersion !== "2.1") {
|
|
3601
|
+
return;
|
|
3602
|
+
}
|
|
3603
|
+
for (const groupId of filter.groupIds) {
|
|
3604
|
+
if (!groupIds.has(groupId)) {
|
|
3605
|
+
diagnostics.push(warn("validate.viewpoint.group.unknown", `Unknown group "${groupId}" in viewpoint "${viewpointId}".`));
|
|
3606
|
+
}
|
|
3607
|
+
}
|
|
3608
|
+
}
|
|
3609
|
+
function validateObject(object, system, objectMap, groupIds, diagnostics) {
|
|
3610
|
+
const placement = object.placement;
|
|
3611
|
+
const orbitPlacement = placement?.mode === "orbit" ? placement : null;
|
|
3612
|
+
const parentObject = placement?.mode === "orbit" ? objectMap.get(placement.target) ?? null : null;
|
|
3613
|
+
if (object.groups) {
|
|
3614
|
+
for (const groupId of object.groups) {
|
|
3615
|
+
if (!groupIds.has(groupId)) {
|
|
3616
|
+
diagnostics.push(warn("validate.group.unknown", `Unknown group "${groupId}" on "${object.id}".`, object.id, "groups"));
|
|
3617
|
+
}
|
|
3618
|
+
}
|
|
3619
|
+
}
|
|
3620
|
+
if (orbitPlacement) {
|
|
3621
|
+
if (!objectMap.has(orbitPlacement.target)) {
|
|
3622
|
+
diagnostics.push(error("validate.orbit.target.unknown", `Unknown placement target "${orbitPlacement.target}" on "${object.id}".`, object.id, "orbit"));
|
|
3623
|
+
}
|
|
3624
|
+
if (orbitPlacement.distance && orbitPlacement.semiMajor) {
|
|
3625
|
+
diagnostics.push(error("validate.orbit.distanceConflict", `Object "${object.id}" cannot declare both "distance" and "semiMajor".`, object.id, "distance"));
|
|
3626
|
+
}
|
|
3627
|
+
if (orbitPlacement.phase && !object.epoch && !system?.epoch) {
|
|
3628
|
+
diagnostics.push(warn("validate.phase.epochMissing", `Object "${object.id}" sets "phase" without an object or system epoch.`, object.id, "phase"));
|
|
3629
|
+
}
|
|
3630
|
+
if (orbitPlacement.inclination && !object.referencePlane && !system?.referencePlane) {
|
|
3631
|
+
diagnostics.push(warn("validate.inclination.referencePlaneMissing", `Object "${object.id}" sets "inclination" without an object or system reference plane.`, object.id, "inclination"));
|
|
3632
|
+
}
|
|
3633
|
+
if (orbitPlacement.period && !massInSolar(parentObject?.properties.mass)) {
|
|
3634
|
+
diagnostics.push(warn("validate.period.massMissing", `Object "${object.id}" sets "period" but its central mass cannot be derived.`, object.id, "period"));
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
if (placement?.mode === "surface") {
|
|
3638
|
+
const target = objectMap.get(placement.target);
|
|
3639
|
+
if (!target) {
|
|
3640
|
+
diagnostics.push(error("validate.surface.target.unknown", `Unknown placement target "${placement.target}" on "${object.id}".`, object.id, "surface"));
|
|
3641
|
+
} else if (!SURFACE_TARGET_TYPES2.has(target.type)) {
|
|
3642
|
+
diagnostics.push(error("validate.surface.target.invalid", `Surface target "${placement.target}" on "${object.id}" is not surface-capable.`, object.id, "surface"));
|
|
3643
|
+
}
|
|
3644
|
+
}
|
|
3645
|
+
if (placement?.mode === "at") {
|
|
3646
|
+
if (object.type !== "structure" && object.type !== "phenomenon") {
|
|
3647
|
+
diagnostics.push(error("validate.at.objectType", `Only structures and phenomena may use "at" placement; found "${object.type}" on "${object.id}".`, object.id, "at"));
|
|
3648
|
+
}
|
|
3649
|
+
if (!validateAtTarget(object, objectMap, diagnostics)) {
|
|
3650
|
+
diagnostics.push(error("validate.at.target.unknown", `Unknown at-reference target "${placement.target}" on "${object.id}".`, object.id, "at"));
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
if (object.resonance) {
|
|
3654
|
+
const target = objectMap.get(object.resonance.targetObjectId);
|
|
3655
|
+
if (!target) {
|
|
3656
|
+
diagnostics.push(error("validate.resonance.target.unknown", `Unknown resonance target "${object.resonance.targetObjectId}" on "${object.id}".`, object.id, "resonance"));
|
|
3657
|
+
} else if (object.placement?.mode !== "orbit" || target.placement?.mode !== "orbit" || object.placement.target !== target.placement.target) {
|
|
3658
|
+
diagnostics.push(warn("validate.resonance.orbitMismatch", `Resonance target "${object.resonance.targetObjectId}" on "${object.id}" does not share a compatible orbital parent.`, object.id, "resonance"));
|
|
3659
|
+
}
|
|
3660
|
+
}
|
|
3661
|
+
for (const rule of object.deriveRules ?? []) {
|
|
3662
|
+
if (rule.field !== "period" || rule.strategy !== "kepler") {
|
|
3663
|
+
diagnostics.push(warn("validate.derive.unsupported", `Unsupported derive rule "${rule.field} ${rule.strategy}" on "${object.id}".`, object.id, "derive"));
|
|
3664
|
+
continue;
|
|
3665
|
+
}
|
|
3666
|
+
const derivedPeriodDays = keplerPeriodDays(object, parentObject);
|
|
3667
|
+
if (derivedPeriodDays === null) {
|
|
3668
|
+
diagnostics.push(warn("validate.derive.inputsMissing", `Object "${object.id}" requests "derive period kepler" but lacks enough input data.`, object.id, "derive"));
|
|
3669
|
+
continue;
|
|
3670
|
+
}
|
|
3671
|
+
if (!orbitPlacement?.period) {
|
|
3672
|
+
diagnostics.push(info("validate.derive.period.available", `Object "${object.id}" can derive a Kepler period of ${formatDays(derivedPeriodDays)}.`, object.id, "derive"));
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3675
|
+
for (const rule of object.validationRules ?? []) {
|
|
3676
|
+
if (rule.rule !== "kepler") {
|
|
3677
|
+
diagnostics.push(warn("validate.rule.unsupported", `Unsupported validation rule "${rule.rule}" on "${object.id}".`, object.id, "validate"));
|
|
3678
|
+
continue;
|
|
3679
|
+
}
|
|
3680
|
+
const actualPeriodDays = durationInDays(orbitPlacement?.period);
|
|
3681
|
+
const derivedPeriodDays = keplerPeriodDays(object, parentObject);
|
|
3682
|
+
if (actualPeriodDays === null || derivedPeriodDays === null) {
|
|
3683
|
+
continue;
|
|
3684
|
+
}
|
|
3685
|
+
const toleranceDays = toleranceForField(object, "period");
|
|
3686
|
+
if (Math.abs(actualPeriodDays - derivedPeriodDays) > toleranceDays) {
|
|
3687
|
+
diagnostics.push(error("validate.kepler.mismatch", `Object "${object.id}" fails Kepler validation for "period".`, object.id, "validate"));
|
|
3688
|
+
}
|
|
3689
|
+
}
|
|
3690
|
+
}
|
|
3691
|
+
function validateAtTarget(object, objectMap, diagnostics) {
|
|
3692
|
+
const reference = object.placement?.mode === "at" ? object.placement.reference : null;
|
|
3693
|
+
if (!reference) {
|
|
3694
|
+
return true;
|
|
3695
|
+
}
|
|
3696
|
+
if (reference.kind === "named") {
|
|
3697
|
+
return objectMap.has(reference.name);
|
|
3698
|
+
}
|
|
3699
|
+
if (reference.kind === "anchor") {
|
|
3700
|
+
if (!objectMap.has(reference.objectId)) {
|
|
3701
|
+
diagnostics.push(error("validate.anchor.target.unknown", `Unknown anchor target "${reference.objectId}" on "${object.id}".`, object.id, "at"));
|
|
3702
|
+
return false;
|
|
3703
|
+
}
|
|
3704
|
+
return true;
|
|
3705
|
+
}
|
|
3706
|
+
if (!objectMap.has(reference.primary)) {
|
|
3707
|
+
diagnostics.push(error("validate.lagrange.primary.unknown", `Unknown Lagrange reference "${reference.primary}" on "${object.id}".`, object.id, "at"));
|
|
3708
|
+
return false;
|
|
3709
|
+
}
|
|
3710
|
+
if (reference.secondary && !objectMap.has(reference.secondary)) {
|
|
3711
|
+
diagnostics.push(error("validate.lagrange.secondary.unknown", `Unknown Lagrange reference "${reference.secondary}" on "${object.id}".`, object.id, "at"));
|
|
3712
|
+
return false;
|
|
3713
|
+
}
|
|
3714
|
+
return true;
|
|
3715
|
+
}
|
|
3716
|
+
function keplerPeriodDays(object, parentObject) {
|
|
3717
|
+
const placement = object.placement;
|
|
3718
|
+
if (!placement || placement.mode !== "orbit") {
|
|
3719
|
+
return null;
|
|
3720
|
+
}
|
|
3721
|
+
const semiMajorAu = distanceInAu(placement.semiMajor ?? placement.distance);
|
|
3722
|
+
const centralMassSolar = massInSolar(parentObject?.properties.mass);
|
|
3723
|
+
if (semiMajorAu === null || centralMassSolar === null || centralMassSolar <= 0) {
|
|
3724
|
+
return null;
|
|
3725
|
+
}
|
|
3726
|
+
const periodYears = Math.sqrt(semiMajorAu ** 3 / centralMassSolar);
|
|
3727
|
+
return periodYears * 365.25;
|
|
3728
|
+
}
|
|
3729
|
+
function distanceInAu(value) {
|
|
3730
|
+
if (!value)
|
|
3731
|
+
return null;
|
|
3732
|
+
switch (value.unit) {
|
|
3733
|
+
case null:
|
|
3734
|
+
case "au":
|
|
3735
|
+
return value.value;
|
|
3736
|
+
case "km":
|
|
3737
|
+
return value.value / AU_IN_KM2;
|
|
3738
|
+
case "m":
|
|
3739
|
+
return value.value / (AU_IN_KM2 * 1e3);
|
|
3740
|
+
case "ly":
|
|
3741
|
+
return value.value * LY_IN_AU2;
|
|
3742
|
+
case "pc":
|
|
3743
|
+
return value.value * PC_IN_AU2;
|
|
3744
|
+
case "kpc":
|
|
3745
|
+
return value.value * KPC_IN_AU2;
|
|
3746
|
+
case "re":
|
|
3747
|
+
return value.value * EARTH_RADIUS_IN_KM2 / AU_IN_KM2;
|
|
3748
|
+
case "sol":
|
|
3749
|
+
return value.value * SOLAR_RADIUS_IN_KM2 / AU_IN_KM2;
|
|
3750
|
+
default:
|
|
3751
|
+
return null;
|
|
3752
|
+
}
|
|
3753
|
+
}
|
|
3754
|
+
function massInSolar(value) {
|
|
3755
|
+
if (!value || typeof value !== "object" || !("value" in value)) {
|
|
3756
|
+
return null;
|
|
3757
|
+
}
|
|
3758
|
+
const unitValue = value;
|
|
3759
|
+
switch (unitValue.unit) {
|
|
3760
|
+
case null:
|
|
3761
|
+
case "sol":
|
|
3762
|
+
return unitValue.value;
|
|
3763
|
+
case "me":
|
|
3764
|
+
return unitValue.value / EARTH_MASSES_PER_SOLAR;
|
|
3765
|
+
case "mj":
|
|
3766
|
+
return unitValue.value / JUPITER_MASSES_PER_SOLAR;
|
|
3767
|
+
default:
|
|
3768
|
+
return null;
|
|
3769
|
+
}
|
|
3770
|
+
}
|
|
3771
|
+
function durationInDays(value) {
|
|
3772
|
+
if (!value)
|
|
3773
|
+
return null;
|
|
3774
|
+
switch (value.unit) {
|
|
3775
|
+
case null:
|
|
3776
|
+
case "d":
|
|
3777
|
+
return value.value;
|
|
3778
|
+
case "s":
|
|
3779
|
+
return value.value / 86400;
|
|
3780
|
+
case "min":
|
|
3781
|
+
return value.value / 1440;
|
|
3782
|
+
case "h":
|
|
3783
|
+
return value.value / 24;
|
|
3784
|
+
case "y":
|
|
3785
|
+
return value.value * 365.25;
|
|
3786
|
+
case "ky":
|
|
3787
|
+
return value.value * 365250;
|
|
3788
|
+
case "my":
|
|
3789
|
+
return value.value * 36525e4;
|
|
3790
|
+
case "gy":
|
|
3791
|
+
return value.value * 36525e7;
|
|
3792
|
+
default:
|
|
3793
|
+
return null;
|
|
3794
|
+
}
|
|
3795
|
+
}
|
|
3796
|
+
function toleranceForField(object, field) {
|
|
3797
|
+
const tolerance = object.tolerances?.find((entry) => entry.field === field)?.value;
|
|
3798
|
+
if (typeof tolerance === "number") {
|
|
3799
|
+
return tolerance;
|
|
3800
|
+
}
|
|
3801
|
+
if (tolerance && typeof tolerance === "object" && "value" in tolerance) {
|
|
3802
|
+
return durationInDays(tolerance) ?? 0;
|
|
3803
|
+
}
|
|
3804
|
+
return 0;
|
|
3805
|
+
}
|
|
3806
|
+
function formatDays(days) {
|
|
3807
|
+
return `${Math.round(days * 100) / 100}d`;
|
|
3808
|
+
}
|
|
3809
|
+
function error(code, message, objectId, field) {
|
|
3810
|
+
return { code, severity: "error", source: "validate", message, objectId, field };
|
|
3811
|
+
}
|
|
3812
|
+
function warn(code, message, objectId, field) {
|
|
3813
|
+
return { code, severity: "warning", source: "validate", message, objectId, field };
|
|
3814
|
+
}
|
|
3815
|
+
function info(code, message, objectId, field) {
|
|
3816
|
+
return { code, severity: "info", source: "validate", message, objectId, field };
|
|
3817
|
+
}
|
|
3818
|
+
|
|
3145
3819
|
// packages/core/dist/draft-parse.js
|
|
3820
|
+
var STRUCTURED_TYPED_BLOCKS = /* @__PURE__ */ new Set([
|
|
3821
|
+
"climate",
|
|
3822
|
+
"habitability",
|
|
3823
|
+
"settlement"
|
|
3824
|
+
]);
|
|
3825
|
+
var DRAFT_OBJECT_FIELD_SPECS = /* @__PURE__ */ new Map();
|
|
3826
|
+
for (const key of [
|
|
3827
|
+
"orbit",
|
|
3828
|
+
"distance",
|
|
3829
|
+
"semiMajor",
|
|
3830
|
+
"eccentricity",
|
|
3831
|
+
"period",
|
|
3832
|
+
"angle",
|
|
3833
|
+
"inclination",
|
|
3834
|
+
"phase",
|
|
3835
|
+
"at",
|
|
3836
|
+
"surface",
|
|
3837
|
+
"free",
|
|
3838
|
+
"kind",
|
|
3839
|
+
"class",
|
|
3840
|
+
"culture",
|
|
3841
|
+
"tags",
|
|
3842
|
+
"color",
|
|
3843
|
+
"image",
|
|
3844
|
+
"hidden",
|
|
3845
|
+
"radius",
|
|
3846
|
+
"mass",
|
|
3847
|
+
"density",
|
|
3848
|
+
"gravity",
|
|
3849
|
+
"temperature",
|
|
3850
|
+
"albedo",
|
|
3851
|
+
"atmosphere",
|
|
3852
|
+
"inner",
|
|
3853
|
+
"outer",
|
|
3854
|
+
"on",
|
|
3855
|
+
"source",
|
|
3856
|
+
"cycle"
|
|
3857
|
+
]) {
|
|
3858
|
+
const schema = getFieldSchema(key);
|
|
3859
|
+
if (schema) {
|
|
3860
|
+
DRAFT_OBJECT_FIELD_SPECS.set(key, {
|
|
3861
|
+
key,
|
|
3862
|
+
version: "2.0",
|
|
3863
|
+
inlineMode: schema.arity === "multiple" ? "multiple" : "single",
|
|
3864
|
+
allowRepeat: false,
|
|
3865
|
+
legacySchema: schema
|
|
3866
|
+
});
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3869
|
+
for (const spec of [
|
|
3870
|
+
{ key: "groups", inlineMode: "multiple", allowRepeat: false },
|
|
3871
|
+
{ key: "epoch", inlineMode: "single", allowRepeat: false },
|
|
3872
|
+
{ key: "referencePlane", inlineMode: "single", allowRepeat: false },
|
|
3873
|
+
{ key: "tidalLock", inlineMode: "single", allowRepeat: false },
|
|
3874
|
+
{ key: "renderLabel", inlineMode: "single", allowRepeat: false },
|
|
3875
|
+
{ key: "renderOrbit", inlineMode: "single", allowRepeat: false },
|
|
3876
|
+
{ key: "renderPriority", inlineMode: "single", allowRepeat: false },
|
|
3877
|
+
{ key: "resonance", inlineMode: "pair", allowRepeat: false },
|
|
3878
|
+
{ key: "derive", inlineMode: "pair", allowRepeat: true },
|
|
3879
|
+
{ key: "validate", inlineMode: "single", allowRepeat: true },
|
|
3880
|
+
{ key: "locked", inlineMode: "multiple", allowRepeat: false },
|
|
3881
|
+
{ key: "tolerance", inlineMode: "pair", allowRepeat: true }
|
|
3882
|
+
]) {
|
|
3883
|
+
DRAFT_OBJECT_FIELD_SPECS.set(spec.key, {
|
|
3884
|
+
key: spec.key,
|
|
3885
|
+
version: "2.1",
|
|
3886
|
+
inlineMode: spec.inlineMode,
|
|
3887
|
+
allowRepeat: spec.allowRepeat
|
|
3888
|
+
});
|
|
3889
|
+
}
|
|
3890
|
+
var DRAFT_OBJECT_FIELD_KEYS = new Set(DRAFT_OBJECT_FIELD_SPECS.keys());
|
|
3146
3891
|
function parseWorldOrbitAtlas(source) {
|
|
3147
|
-
return parseAtlasSource(source
|
|
3892
|
+
return parseAtlasSource(source);
|
|
3148
3893
|
}
|
|
3149
3894
|
function parseWorldOrbitDraft(source) {
|
|
3150
3895
|
return parseAtlasSource(source, "2.0-draft");
|
|
3151
3896
|
}
|
|
3152
|
-
function parseAtlasSource(source,
|
|
3153
|
-
const
|
|
3897
|
+
function parseAtlasSource(source, forcedOutputVersion) {
|
|
3898
|
+
const prepared = preprocessAtlasSource(source);
|
|
3899
|
+
const lines = prepared.source.split(/\r?\n/);
|
|
3900
|
+
const diagnostics = [];
|
|
3154
3901
|
let sawSchemaHeader = false;
|
|
3155
|
-
let
|
|
3902
|
+
let sourceSchemaVersion = "2.0";
|
|
3156
3903
|
let system = null;
|
|
3157
3904
|
let section = null;
|
|
3158
3905
|
const objectNodes = [];
|
|
3906
|
+
const groups = [];
|
|
3907
|
+
const relations = [];
|
|
3159
3908
|
let sawDefaults = false;
|
|
3160
3909
|
let sawAtlas = false;
|
|
3161
3910
|
const viewpointIds = /* @__PURE__ */ new Set();
|
|
3162
3911
|
const annotationIds = /* @__PURE__ */ new Set();
|
|
3912
|
+
const groupIds = /* @__PURE__ */ new Set();
|
|
3913
|
+
const relationIds = /* @__PURE__ */ new Set();
|
|
3163
3914
|
for (let index = 0; index < lines.length; index++) {
|
|
3164
3915
|
const rawLine = lines[index];
|
|
3165
3916
|
const lineNumber = index + 1;
|
|
@@ -3175,15 +3926,22 @@ var WorldOrbit = (() => {
|
|
|
3175
3926
|
continue;
|
|
3176
3927
|
}
|
|
3177
3928
|
if (!sawSchemaHeader) {
|
|
3178
|
-
|
|
3929
|
+
sourceSchemaVersion = assertDraftSchemaHeader(tokens, lineNumber);
|
|
3179
3930
|
sawSchemaHeader = true;
|
|
3931
|
+
if (prepared.comments.length > 0 && sourceSchemaVersion !== "2.1") {
|
|
3932
|
+
diagnostics.push({
|
|
3933
|
+
code: "parse.schema21.commentCompatibility",
|
|
3934
|
+
severity: "warning",
|
|
3935
|
+
source: "parse",
|
|
3936
|
+
message: `Comments require schema 2.1; parsed in compatibility mode because the document header is "schema ${sourceSchemaVersion}".`,
|
|
3937
|
+
line: prepared.comments[0].line,
|
|
3938
|
+
column: prepared.comments[0].column
|
|
3939
|
+
});
|
|
3940
|
+
}
|
|
3180
3941
|
continue;
|
|
3181
3942
|
}
|
|
3182
3943
|
if (indent === 0) {
|
|
3183
|
-
section = startTopLevelSection(tokens, lineNumber, system, objectNodes, viewpointIds, annotationIds, {
|
|
3184
|
-
sawDefaults,
|
|
3185
|
-
sawAtlas
|
|
3186
|
-
});
|
|
3944
|
+
section = startTopLevelSection(tokens, lineNumber, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, { sawDefaults, sawAtlas });
|
|
3187
3945
|
if (section.kind === "system") {
|
|
3188
3946
|
system = section.system;
|
|
3189
3947
|
} else if (section.kind === "defaults") {
|
|
@@ -3201,48 +3959,57 @@ var WorldOrbit = (() => {
|
|
|
3201
3959
|
if (!sawSchemaHeader) {
|
|
3202
3960
|
throw new WorldOrbitError('Missing required atlas schema header "schema 2.0"');
|
|
3203
3961
|
}
|
|
3204
|
-
const
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
};
|
|
3208
|
-
const normalizedObjects = normalizeDocument(ast).objects;
|
|
3209
|
-
validateDocument({
|
|
3210
|
-
format: "worldorbit",
|
|
3211
|
-
version: "1.0",
|
|
3212
|
-
system: null,
|
|
3213
|
-
objects: normalizedObjects
|
|
3214
|
-
});
|
|
3215
|
-
const diagnostics = schemaVersion === "2.0-draft" && outputVersion === "2.0" ? [
|
|
3216
|
-
{
|
|
3217
|
-
code: "load.schema.deprecatedDraft",
|
|
3218
|
-
severity: "warning",
|
|
3219
|
-
source: "upgrade",
|
|
3220
|
-
message: 'Source header "schema 2.0-draft" is deprecated; canonical v2 documents now use "schema 2.0".'
|
|
3221
|
-
}
|
|
3222
|
-
] : [];
|
|
3223
|
-
return {
|
|
3962
|
+
const objects = objectNodes.map((node) => normalizeDraftObject(node, sourceSchemaVersion, diagnostics));
|
|
3963
|
+
const outputVersion = forcedOutputVersion ?? (sourceSchemaVersion === "2.0-draft" ? "2.0" : sourceSchemaVersion);
|
|
3964
|
+
const baseDocument = {
|
|
3224
3965
|
format: "worldorbit",
|
|
3225
|
-
version: outputVersion,
|
|
3226
3966
|
sourceVersion: "1.0",
|
|
3227
3967
|
system,
|
|
3228
|
-
|
|
3968
|
+
groups,
|
|
3969
|
+
relations,
|
|
3970
|
+
objects,
|
|
3229
3971
|
diagnostics
|
|
3230
3972
|
};
|
|
3973
|
+
if (outputVersion === "2.0-draft") {
|
|
3974
|
+
const document3 = {
|
|
3975
|
+
...baseDocument,
|
|
3976
|
+
version: "2.0-draft",
|
|
3977
|
+
schemaVersion: "2.0-draft"
|
|
3978
|
+
};
|
|
3979
|
+
document3.diagnostics.push(...collectAtlasDiagnostics(document3, sourceSchemaVersion));
|
|
3980
|
+
return document3;
|
|
3981
|
+
}
|
|
3982
|
+
const document2 = {
|
|
3983
|
+
...baseDocument,
|
|
3984
|
+
version: outputVersion,
|
|
3985
|
+
schemaVersion: outputVersion
|
|
3986
|
+
};
|
|
3987
|
+
if (sourceSchemaVersion === "2.0-draft") {
|
|
3988
|
+
document2.diagnostics.push({
|
|
3989
|
+
code: "load.schema.deprecatedDraft",
|
|
3990
|
+
severity: "warning",
|
|
3991
|
+
source: "upgrade",
|
|
3992
|
+
message: 'Source header "schema 2.0-draft" is deprecated; canonical v2 documents now use "schema 2.0".'
|
|
3993
|
+
});
|
|
3994
|
+
}
|
|
3995
|
+
document2.diagnostics.push(...collectAtlasDiagnostics(document2, sourceSchemaVersion));
|
|
3996
|
+
return document2;
|
|
3231
3997
|
}
|
|
3232
3998
|
function assertDraftSchemaHeader(tokens, line) {
|
|
3233
|
-
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "schema" ||
|
|
3234
|
-
throw new WorldOrbitError('Expected atlas header "schema 2.0" or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
|
|
3999
|
+
if (tokens.length !== 2 || tokens[0].value.toLowerCase() !== "schema" || !["2.0-draft", "2.0", "2.1"].includes(tokens[1].value.toLowerCase())) {
|
|
4000
|
+
throw new WorldOrbitError('Expected atlas header "schema 2.0", "schema 2.1", or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
|
|
3235
4001
|
}
|
|
3236
|
-
|
|
4002
|
+
const version = tokens[1].value.toLowerCase();
|
|
4003
|
+
return version === "2.1" ? "2.1" : version === "2.0-draft" ? "2.0-draft" : "2.0";
|
|
3237
4004
|
}
|
|
3238
|
-
function startTopLevelSection(tokens, line, system, objectNodes, viewpointIds, annotationIds, flags) {
|
|
4005
|
+
function startTopLevelSection(tokens, line, sourceSchemaVersion, diagnostics, system, objectNodes, groups, relations, viewpointIds, annotationIds, groupIds, relationIds, flags) {
|
|
3239
4006
|
const keyword = tokens[0]?.value.toLowerCase();
|
|
3240
4007
|
switch (keyword) {
|
|
3241
4008
|
case "system":
|
|
3242
4009
|
if (system) {
|
|
3243
4010
|
throw new WorldOrbitError('Atlas section "system" may only appear once', line, tokens[0].column);
|
|
3244
4011
|
}
|
|
3245
|
-
return startSystemSection(tokens, line);
|
|
4012
|
+
return startSystemSection(tokens, line, sourceSchemaVersion, diagnostics);
|
|
3246
4013
|
case "defaults":
|
|
3247
4014
|
if (!system) {
|
|
3248
4015
|
throw new WorldOrbitError('Atlas section "defaults" requires a preceding system declaration', line, tokens[0].column);
|
|
@@ -3278,13 +4045,19 @@ var WorldOrbit = (() => {
|
|
|
3278
4045
|
throw new WorldOrbitError('Atlas section "annotation" requires a preceding system declaration', line, tokens[0].column);
|
|
3279
4046
|
}
|
|
3280
4047
|
return startAnnotationSection(tokens, line, system, annotationIds);
|
|
4048
|
+
case "group":
|
|
4049
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "group", { line, column: tokens[0].column });
|
|
4050
|
+
return startGroupSection(tokens, line, groups, groupIds);
|
|
4051
|
+
case "relation":
|
|
4052
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, "relation", { line, column: tokens[0].column });
|
|
4053
|
+
return startRelationSection(tokens, line, relations, relationIds);
|
|
3281
4054
|
case "object":
|
|
3282
|
-
return startObjectSection(tokens, line, objectNodes);
|
|
4055
|
+
return startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes);
|
|
3283
4056
|
default:
|
|
3284
4057
|
throw new WorldOrbitError(`Unknown atlas section "${tokens[0]?.value ?? ""}"`, line, tokens[0]?.column ?? 1);
|
|
3285
4058
|
}
|
|
3286
4059
|
}
|
|
3287
|
-
function startSystemSection(tokens, line) {
|
|
4060
|
+
function startSystemSection(tokens, line, sourceSchemaVersion, diagnostics) {
|
|
3288
4061
|
if (tokens.length !== 2) {
|
|
3289
4062
|
throw new WorldOrbitError("Invalid atlas system declaration", line, tokens[0]?.column ?? 1);
|
|
3290
4063
|
}
|
|
@@ -3292,6 +4065,9 @@ var WorldOrbit = (() => {
|
|
|
3292
4065
|
type: "system",
|
|
3293
4066
|
id: tokens[1].value,
|
|
3294
4067
|
title: null,
|
|
4068
|
+
description: null,
|
|
4069
|
+
epoch: null,
|
|
4070
|
+
referencePlane: null,
|
|
3295
4071
|
defaults: {
|
|
3296
4072
|
view: "topdown",
|
|
3297
4073
|
scale: null,
|
|
@@ -3306,6 +4082,8 @@ var WorldOrbit = (() => {
|
|
|
3306
4082
|
return {
|
|
3307
4083
|
kind: "system",
|
|
3308
4084
|
system,
|
|
4085
|
+
sourceSchemaVersion,
|
|
4086
|
+
diagnostics,
|
|
3309
4087
|
seenFields: /* @__PURE__ */ new Set()
|
|
3310
4088
|
};
|
|
3311
4089
|
}
|
|
@@ -3371,7 +4149,64 @@ var WorldOrbit = (() => {
|
|
|
3371
4149
|
seenFields: /* @__PURE__ */ new Set()
|
|
3372
4150
|
};
|
|
3373
4151
|
}
|
|
3374
|
-
function
|
|
4152
|
+
function startGroupSection(tokens, line, groups, groupIds) {
|
|
4153
|
+
if (tokens.length !== 2) {
|
|
4154
|
+
throw new WorldOrbitError("Invalid group declaration", line, tokens[0]?.column ?? 1);
|
|
4155
|
+
}
|
|
4156
|
+
const id = normalizeIdentifier2(tokens[1].value);
|
|
4157
|
+
if (!id) {
|
|
4158
|
+
throw new WorldOrbitError("Group id must not be empty", line, tokens[1].column);
|
|
4159
|
+
}
|
|
4160
|
+
if (groupIds.has(id)) {
|
|
4161
|
+
throw new WorldOrbitError(`Duplicate group id "${id}"`, line, tokens[1].column);
|
|
4162
|
+
}
|
|
4163
|
+
const group = {
|
|
4164
|
+
id,
|
|
4165
|
+
label: humanizeIdentifier3(id),
|
|
4166
|
+
summary: "",
|
|
4167
|
+
color: null,
|
|
4168
|
+
tags: [],
|
|
4169
|
+
hidden: false
|
|
4170
|
+
};
|
|
4171
|
+
groups.push(group);
|
|
4172
|
+
groupIds.add(id);
|
|
4173
|
+
return {
|
|
4174
|
+
kind: "group",
|
|
4175
|
+
group,
|
|
4176
|
+
seenFields: /* @__PURE__ */ new Set()
|
|
4177
|
+
};
|
|
4178
|
+
}
|
|
4179
|
+
function startRelationSection(tokens, line, relations, relationIds) {
|
|
4180
|
+
if (tokens.length !== 2) {
|
|
4181
|
+
throw new WorldOrbitError("Invalid relation declaration", line, tokens[0]?.column ?? 1);
|
|
4182
|
+
}
|
|
4183
|
+
const id = normalizeIdentifier2(tokens[1].value);
|
|
4184
|
+
if (!id) {
|
|
4185
|
+
throw new WorldOrbitError("Relation id must not be empty", line, tokens[1].column);
|
|
4186
|
+
}
|
|
4187
|
+
if (relationIds.has(id)) {
|
|
4188
|
+
throw new WorldOrbitError(`Duplicate relation id "${id}"`, line, tokens[1].column);
|
|
4189
|
+
}
|
|
4190
|
+
const relation = {
|
|
4191
|
+
id,
|
|
4192
|
+
from: "",
|
|
4193
|
+
to: "",
|
|
4194
|
+
kind: "",
|
|
4195
|
+
label: null,
|
|
4196
|
+
summary: null,
|
|
4197
|
+
tags: [],
|
|
4198
|
+
color: null,
|
|
4199
|
+
hidden: false
|
|
4200
|
+
};
|
|
4201
|
+
relations.push(relation);
|
|
4202
|
+
relationIds.add(id);
|
|
4203
|
+
return {
|
|
4204
|
+
kind: "relation",
|
|
4205
|
+
relation,
|
|
4206
|
+
seenFields: /* @__PURE__ */ new Set()
|
|
4207
|
+
};
|
|
4208
|
+
}
|
|
4209
|
+
function startObjectSection(tokens, line, sourceSchemaVersion, diagnostics, objectNodes) {
|
|
3375
4210
|
if (tokens.length < 3) {
|
|
3376
4211
|
throw new WorldOrbitError("Invalid atlas object declaration", line, tokens[0]?.column ?? 1);
|
|
3377
4212
|
}
|
|
@@ -3382,12 +4217,11 @@ var WorldOrbit = (() => {
|
|
|
3382
4217
|
throw new WorldOrbitError(`Unknown object type "${objectTypeToken.value}"`, line, objectTypeToken.column);
|
|
3383
4218
|
}
|
|
3384
4219
|
const objectNode = {
|
|
3385
|
-
type: "object",
|
|
3386
4220
|
objectType,
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
blockFields: [],
|
|
4221
|
+
id: idToken.value,
|
|
4222
|
+
fields: parseInlineObjectFields(tokens.slice(3), line, objectType, sourceSchemaVersion, diagnostics),
|
|
3390
4223
|
infoEntries: [],
|
|
4224
|
+
typedBlockEntries: {},
|
|
3391
4225
|
location: {
|
|
3392
4226
|
line,
|
|
3393
4227
|
column: objectTypeToken.column
|
|
@@ -3397,8 +4231,12 @@ var WorldOrbit = (() => {
|
|
|
3397
4231
|
return {
|
|
3398
4232
|
kind: "object",
|
|
3399
4233
|
objectNode,
|
|
3400
|
-
|
|
3401
|
-
|
|
4234
|
+
sourceSchemaVersion,
|
|
4235
|
+
diagnostics,
|
|
4236
|
+
activeBlock: null,
|
|
4237
|
+
blockIndent: null,
|
|
4238
|
+
seenInfoKeys: /* @__PURE__ */ new Set(),
|
|
4239
|
+
seenTypedBlockKeys: {}
|
|
3402
4240
|
};
|
|
3403
4241
|
}
|
|
3404
4242
|
function handleSectionLine(section, indent, tokens, line) {
|
|
@@ -3418,6 +4256,12 @@ var WorldOrbit = (() => {
|
|
|
3418
4256
|
case "annotation":
|
|
3419
4257
|
applyAnnotationField(section, tokens, line);
|
|
3420
4258
|
return;
|
|
4259
|
+
case "group":
|
|
4260
|
+
applyGroupField(section, tokens, line);
|
|
4261
|
+
return;
|
|
4262
|
+
case "relation":
|
|
4263
|
+
applyRelationField(section, tokens, line);
|
|
4264
|
+
return;
|
|
3421
4265
|
case "object":
|
|
3422
4266
|
applyObjectField(section, indent, tokens, line);
|
|
3423
4267
|
return;
|
|
@@ -3425,10 +4269,35 @@ var WorldOrbit = (() => {
|
|
|
3425
4269
|
}
|
|
3426
4270
|
function applySystemField(section, tokens, line) {
|
|
3427
4271
|
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
3428
|
-
|
|
3429
|
-
|
|
4272
|
+
const value = joinFieldValue(tokens, line);
|
|
4273
|
+
switch (key) {
|
|
4274
|
+
case "title":
|
|
4275
|
+
section.system.title = value;
|
|
4276
|
+
return;
|
|
4277
|
+
case "description":
|
|
4278
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, key, {
|
|
4279
|
+
line,
|
|
4280
|
+
column: tokens[0].column
|
|
4281
|
+
});
|
|
4282
|
+
section.system.description = value;
|
|
4283
|
+
return;
|
|
4284
|
+
case "epoch":
|
|
4285
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, key, {
|
|
4286
|
+
line,
|
|
4287
|
+
column: tokens[0].column
|
|
4288
|
+
});
|
|
4289
|
+
section.system.epoch = value;
|
|
4290
|
+
return;
|
|
4291
|
+
case "referenceplane":
|
|
4292
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, "referencePlane", {
|
|
4293
|
+
line,
|
|
4294
|
+
column: tokens[0].column
|
|
4295
|
+
});
|
|
4296
|
+
section.system.referencePlane = value;
|
|
4297
|
+
return;
|
|
4298
|
+
default:
|
|
4299
|
+
throw new WorldOrbitError(`Unknown system atlas field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3430
4300
|
}
|
|
3431
|
-
section.system.title = joinFieldValue(tokens, line);
|
|
3432
4301
|
}
|
|
3433
4302
|
function applyDefaultsField(section, tokens, line) {
|
|
3434
4303
|
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
@@ -3459,14 +4328,11 @@ var WorldOrbit = (() => {
|
|
|
3459
4328
|
section.metadataIndent = null;
|
|
3460
4329
|
}
|
|
3461
4330
|
if (section.inMetadata) {
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
const key = tokens[0].value;
|
|
3466
|
-
if (key in section.system.atlasMetadata) {
|
|
3467
|
-
throw new WorldOrbitError(`Duplicate atlas metadata key "${key}"`, line, tokens[0].column);
|
|
4331
|
+
const entry = parseInfoLikeEntry(tokens, line, "Invalid atlas metadata entry");
|
|
4332
|
+
if (entry.key in section.system.atlasMetadata) {
|
|
4333
|
+
throw new WorldOrbitError(`Duplicate atlas metadata key "${entry.key}"`, line, tokens[0].column);
|
|
3468
4334
|
}
|
|
3469
|
-
section.system.atlasMetadata[key] =
|
|
4335
|
+
section.system.atlasMetadata[entry.key] = entry.value;
|
|
3470
4336
|
return;
|
|
3471
4337
|
}
|
|
3472
4338
|
if (tokens.length === 1 && tokens[0].value.toLowerCase() === "metadata") {
|
|
@@ -3562,27 +4428,108 @@ var WorldOrbit = (() => {
|
|
|
3562
4428
|
section.annotation.body = joinFieldValue(tokens, line);
|
|
3563
4429
|
return;
|
|
3564
4430
|
case "tags":
|
|
3565
|
-
section.annotation.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
4431
|
+
section.annotation.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
4432
|
+
return;
|
|
4433
|
+
default:
|
|
4434
|
+
throw new WorldOrbitError(`Unknown annotation field "${tokens[0].value}"`, line, tokens[0].column);
|
|
4435
|
+
}
|
|
4436
|
+
}
|
|
4437
|
+
function applyGroupField(section, tokens, line) {
|
|
4438
|
+
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
4439
|
+
switch (key) {
|
|
4440
|
+
case "label":
|
|
4441
|
+
section.group.label = joinFieldValue(tokens, line);
|
|
4442
|
+
return;
|
|
4443
|
+
case "summary":
|
|
4444
|
+
section.group.summary = joinFieldValue(tokens, line);
|
|
4445
|
+
return;
|
|
4446
|
+
case "color":
|
|
4447
|
+
section.group.color = joinFieldValue(tokens, line);
|
|
4448
|
+
return;
|
|
4449
|
+
case "tags":
|
|
4450
|
+
section.group.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
4451
|
+
return;
|
|
4452
|
+
case "hidden":
|
|
4453
|
+
section.group.hidden = parseAtlasBoolean(joinFieldValue(tokens, line), "hidden", {
|
|
4454
|
+
line,
|
|
4455
|
+
column: tokens[0].column
|
|
4456
|
+
});
|
|
4457
|
+
return;
|
|
4458
|
+
default:
|
|
4459
|
+
throw new WorldOrbitError(`Unknown group field "${tokens[0].value}"`, line, tokens[0].column);
|
|
4460
|
+
}
|
|
4461
|
+
}
|
|
4462
|
+
function applyRelationField(section, tokens, line) {
|
|
4463
|
+
const key = requireUniqueField(tokens, section.seenFields, line);
|
|
4464
|
+
switch (key) {
|
|
4465
|
+
case "from":
|
|
4466
|
+
section.relation.from = joinFieldValue(tokens, line);
|
|
4467
|
+
return;
|
|
4468
|
+
case "to":
|
|
4469
|
+
section.relation.to = joinFieldValue(tokens, line);
|
|
4470
|
+
return;
|
|
4471
|
+
case "kind":
|
|
4472
|
+
section.relation.kind = joinFieldValue(tokens, line);
|
|
4473
|
+
return;
|
|
4474
|
+
case "label":
|
|
4475
|
+
section.relation.label = joinFieldValue(tokens, line);
|
|
4476
|
+
return;
|
|
4477
|
+
case "summary":
|
|
4478
|
+
section.relation.summary = joinFieldValue(tokens, line);
|
|
4479
|
+
return;
|
|
4480
|
+
case "tags":
|
|
4481
|
+
section.relation.tags = parseTokenList(tokens.slice(1), line, "tags");
|
|
4482
|
+
return;
|
|
4483
|
+
case "color":
|
|
4484
|
+
section.relation.color = joinFieldValue(tokens, line);
|
|
4485
|
+
return;
|
|
4486
|
+
case "hidden":
|
|
4487
|
+
section.relation.hidden = parseAtlasBoolean(joinFieldValue(tokens, line), "hidden", {
|
|
4488
|
+
line,
|
|
4489
|
+
column: tokens[0].column
|
|
4490
|
+
});
|
|
3566
4491
|
return;
|
|
3567
4492
|
default:
|
|
3568
|
-
throw new WorldOrbitError(`Unknown
|
|
4493
|
+
throw new WorldOrbitError(`Unknown relation field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3569
4494
|
}
|
|
3570
4495
|
}
|
|
3571
4496
|
function applyObjectField(section, indent, tokens, line) {
|
|
3572
|
-
if (
|
|
3573
|
-
section.
|
|
3574
|
-
section.
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
4497
|
+
if (section.activeBlock && indent <= (section.blockIndent ?? 0)) {
|
|
4498
|
+
section.activeBlock = null;
|
|
4499
|
+
section.blockIndent = null;
|
|
4500
|
+
}
|
|
4501
|
+
if (tokens.length === 1) {
|
|
4502
|
+
const blockName = tokens[0].value.toLowerCase();
|
|
4503
|
+
if (blockName === "info" || STRUCTURED_TYPED_BLOCKS.has(blockName)) {
|
|
4504
|
+
if (blockName !== "info") {
|
|
4505
|
+
warnIfSchema21Feature(section.sourceSchemaVersion, section.diagnostics, blockName, { line, column: tokens[0].column });
|
|
4506
|
+
}
|
|
4507
|
+
section.activeBlock = blockName;
|
|
4508
|
+
section.blockIndent = indent;
|
|
4509
|
+
return;
|
|
4510
|
+
}
|
|
3580
4511
|
}
|
|
3581
|
-
if (section.
|
|
3582
|
-
|
|
4512
|
+
if (section.activeBlock) {
|
|
4513
|
+
const entry = parseInfoLikeEntry(tokens, line, `Invalid ${section.activeBlock} entry`);
|
|
4514
|
+
if (section.activeBlock === "info") {
|
|
4515
|
+
if (section.seenInfoKeys.has(entry.key)) {
|
|
4516
|
+
throw new WorldOrbitError(`Duplicate info key "${entry.key}"`, line, tokens[0].column);
|
|
4517
|
+
}
|
|
4518
|
+
section.seenInfoKeys.add(entry.key);
|
|
4519
|
+
section.objectNode.infoEntries.push(entry);
|
|
4520
|
+
return;
|
|
4521
|
+
}
|
|
4522
|
+
const typedBlock = section.activeBlock;
|
|
4523
|
+
const seenKeys = section.seenTypedBlockKeys[typedBlock] ?? (section.seenTypedBlockKeys[typedBlock] = /* @__PURE__ */ new Set());
|
|
4524
|
+
if (seenKeys.has(entry.key)) {
|
|
4525
|
+
throw new WorldOrbitError(`Duplicate ${typedBlock} key "${entry.key}"`, line, tokens[0].column);
|
|
4526
|
+
}
|
|
4527
|
+
seenKeys.add(entry.key);
|
|
4528
|
+
const entries = section.objectNode.typedBlockEntries[typedBlock] ?? (section.objectNode.typedBlockEntries[typedBlock] = []);
|
|
4529
|
+
entries.push(entry);
|
|
3583
4530
|
return;
|
|
3584
4531
|
}
|
|
3585
|
-
section.objectNode.
|
|
4532
|
+
section.objectNode.fields.push(parseObjectField(tokens, line, section.objectNode.objectType, section.sourceSchemaVersion, section.diagnostics));
|
|
3586
4533
|
}
|
|
3587
4534
|
function requireUniqueField(tokens, seenFields, line) {
|
|
3588
4535
|
if (tokens.length < 2) {
|
|
@@ -3602,50 +4549,40 @@ var WorldOrbit = (() => {
|
|
|
3602
4549
|
return tokens.slice(1).map((token) => token.value).join(" ").trim();
|
|
3603
4550
|
}
|
|
3604
4551
|
function parseObjectTypeTokens(tokens, line) {
|
|
3605
|
-
|
|
3606
|
-
throw new WorldOrbitError("Missing value for atlas field", line);
|
|
3607
|
-
}
|
|
3608
|
-
return tokens.map((token) => {
|
|
3609
|
-
const value = token.value;
|
|
3610
|
-
if (value !== "star" && value !== "planet" && value !== "moon" && value !== "belt" && value !== "asteroid" && value !== "comet" && value !== "ring" && value !== "structure" && value !== "phenomenon") {
|
|
3611
|
-
throw new WorldOrbitError(`Unknown viewpoint object type "${token.value}"`, line, token.column);
|
|
3612
|
-
}
|
|
3613
|
-
return value;
|
|
3614
|
-
});
|
|
3615
|
-
}
|
|
3616
|
-
function parseTokenList(tokens, line, field) {
|
|
3617
|
-
if (tokens.length === 0) {
|
|
3618
|
-
throw new WorldOrbitError(`Missing value for field "${field}"`, line);
|
|
3619
|
-
}
|
|
3620
|
-
return tokens.map((token) => token.value);
|
|
4552
|
+
return parseTokenList(tokens, line, "objectTypes").filter((value) => value === "star" || value === "planet" || value === "moon" || value === "belt" || value === "asteroid" || value === "comet" || value === "ring" || value === "structure" || value === "phenomenon");
|
|
3621
4553
|
}
|
|
3622
4554
|
function parseLayerTokens(tokens, line) {
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
if (rawLayer === "orbits") {
|
|
3631
|
-
next["orbits-back"] = enabled;
|
|
3632
|
-
next["orbits-front"] = enabled;
|
|
4555
|
+
const layers = {};
|
|
4556
|
+
for (const token of parseTokenList(tokens, line, "layers")) {
|
|
4557
|
+
const enabled = !token.startsWith("-") && !token.startsWith("!");
|
|
4558
|
+
const raw = token.replace(/^[-!]+/, "").toLowerCase();
|
|
4559
|
+
if (raw === "orbits") {
|
|
4560
|
+
layers["orbits-back"] = enabled;
|
|
4561
|
+
layers["orbits-front"] = enabled;
|
|
3633
4562
|
continue;
|
|
3634
4563
|
}
|
|
3635
|
-
if (
|
|
3636
|
-
|
|
3637
|
-
continue;
|
|
4564
|
+
if (raw === "background" || raw === "guides" || raw === "orbits-back" || raw === "orbits-front" || raw === "relations" || raw === "objects" || raw === "labels" || raw === "metadata") {
|
|
4565
|
+
layers[raw] = enabled;
|
|
3638
4566
|
}
|
|
3639
|
-
throw new WorldOrbitError(`Unknown layer token "${token.value}"`, line, token.column);
|
|
3640
4567
|
}
|
|
3641
|
-
return
|
|
4568
|
+
return layers;
|
|
4569
|
+
}
|
|
4570
|
+
function parseTokenList(tokens, line, fieldName) {
|
|
4571
|
+
if (tokens.length === 0) {
|
|
4572
|
+
throw new WorldOrbitError(`Missing value for atlas field "${fieldName}"`, line, 1);
|
|
4573
|
+
}
|
|
4574
|
+
const values = tokens.map((token) => token.value).filter(Boolean);
|
|
4575
|
+
if (values.length === 0) {
|
|
4576
|
+
throw new WorldOrbitError(`Missing value for atlas field "${fieldName}"`, line, tokens[0]?.column ?? 1);
|
|
4577
|
+
}
|
|
4578
|
+
return values;
|
|
3642
4579
|
}
|
|
3643
4580
|
function parseProjectionValue(value, line, column) {
|
|
3644
4581
|
const normalized = value.toLowerCase();
|
|
3645
|
-
if (normalized
|
|
3646
|
-
|
|
4582
|
+
if (normalized !== "topdown" && normalized !== "isometric") {
|
|
4583
|
+
throw new WorldOrbitError(`Unknown projection "${value}"`, line, column);
|
|
3647
4584
|
}
|
|
3648
|
-
|
|
4585
|
+
return normalized;
|
|
3649
4586
|
}
|
|
3650
4587
|
function parsePresetValue(value, line, column) {
|
|
3651
4588
|
const normalized = value.toLowerCase();
|
|
@@ -3655,16 +4592,16 @@ var WorldOrbit = (() => {
|
|
|
3655
4592
|
throw new WorldOrbitError(`Unknown render preset "${value}"`, line, column);
|
|
3656
4593
|
}
|
|
3657
4594
|
function parsePositiveNumber2(value, line, column, field) {
|
|
3658
|
-
const parsed =
|
|
3659
|
-
if (
|
|
3660
|
-
throw new WorldOrbitError(`Field "${field}"
|
|
4595
|
+
const parsed = parseFiniteNumber2(value, line, column, field);
|
|
4596
|
+
if (parsed <= 0) {
|
|
4597
|
+
throw new WorldOrbitError(`Field "${field}" must be greater than zero`, line, column);
|
|
3661
4598
|
}
|
|
3662
4599
|
return parsed;
|
|
3663
4600
|
}
|
|
3664
4601
|
function parseFiniteNumber2(value, line, column, field) {
|
|
3665
4602
|
const parsed = Number(value);
|
|
3666
4603
|
if (!Number.isFinite(parsed)) {
|
|
3667
|
-
throw new WorldOrbitError(`
|
|
4604
|
+
throw new WorldOrbitError(`Invalid numeric value "${value}" for "${field}"`, line, column);
|
|
3668
4605
|
}
|
|
3669
4606
|
return parsed;
|
|
3670
4607
|
}
|
|
@@ -3676,28 +4613,43 @@ var WorldOrbit = (() => {
|
|
|
3676
4613
|
groupIds: []
|
|
3677
4614
|
};
|
|
3678
4615
|
}
|
|
3679
|
-
function
|
|
4616
|
+
function parseInlineObjectFields(tokens, line, objectType, sourceSchemaVersion, diagnostics) {
|
|
3680
4617
|
const fields = [];
|
|
3681
4618
|
let index = 0;
|
|
3682
4619
|
while (index < tokens.length) {
|
|
3683
4620
|
const keyToken = tokens[index];
|
|
3684
|
-
const
|
|
3685
|
-
if (!
|
|
4621
|
+
const spec = getDraftObjectFieldSpec(keyToken.value);
|
|
4622
|
+
if (!spec) {
|
|
3686
4623
|
throw new WorldOrbitError(`Unknown field "${keyToken.value}"`, line, keyToken.column);
|
|
3687
4624
|
}
|
|
4625
|
+
if (spec.version === "2.1") {
|
|
4626
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, keyToken.value, {
|
|
4627
|
+
line,
|
|
4628
|
+
column: keyToken.column
|
|
4629
|
+
});
|
|
4630
|
+
}
|
|
3688
4631
|
index++;
|
|
3689
4632
|
const valueTokens = [];
|
|
3690
|
-
if (
|
|
3691
|
-
while (index < tokens.length && !isKnownFieldKey(tokens[index].value)) {
|
|
3692
|
-
valueTokens.push(tokens[index]);
|
|
3693
|
-
index++;
|
|
3694
|
-
}
|
|
3695
|
-
} else {
|
|
4633
|
+
if (spec.inlineMode === "single") {
|
|
3696
4634
|
const nextToken = tokens[index];
|
|
3697
4635
|
if (nextToken) {
|
|
3698
4636
|
valueTokens.push(nextToken);
|
|
3699
4637
|
index++;
|
|
3700
4638
|
}
|
|
4639
|
+
} else if (spec.inlineMode === "pair") {
|
|
4640
|
+
for (let count = 0; count < 2; count++) {
|
|
4641
|
+
const nextToken = tokens[index];
|
|
4642
|
+
if (!nextToken) {
|
|
4643
|
+
break;
|
|
4644
|
+
}
|
|
4645
|
+
valueTokens.push(nextToken);
|
|
4646
|
+
index++;
|
|
4647
|
+
}
|
|
4648
|
+
} else {
|
|
4649
|
+
while (index < tokens.length && !DRAFT_OBJECT_FIELD_KEYS.has(tokens[index].value)) {
|
|
4650
|
+
valueTokens.push(tokens[index]);
|
|
4651
|
+
index++;
|
|
4652
|
+
}
|
|
3701
4653
|
}
|
|
3702
4654
|
if (valueTokens.length === 0) {
|
|
3703
4655
|
throw new WorldOrbitError(`Missing value for field "${keyToken.value}"`, line, keyToken.column);
|
|
@@ -3709,25 +4661,35 @@ var WorldOrbit = (() => {
|
|
|
3709
4661
|
location: { line, column: keyToken.column }
|
|
3710
4662
|
});
|
|
3711
4663
|
}
|
|
4664
|
+
validateDraftObjectFieldCompatibility(fields, objectType);
|
|
3712
4665
|
return fields;
|
|
3713
4666
|
}
|
|
3714
|
-
function
|
|
4667
|
+
function parseObjectField(tokens, line, objectType, sourceSchemaVersion, diagnostics) {
|
|
3715
4668
|
if (tokens.length < 2) {
|
|
3716
4669
|
throw new WorldOrbitError("Invalid field line", line, tokens[0]?.column ?? 1);
|
|
3717
4670
|
}
|
|
3718
|
-
|
|
4671
|
+
const spec = getDraftObjectFieldSpec(tokens[0].value);
|
|
4672
|
+
if (!spec) {
|
|
3719
4673
|
throw new WorldOrbitError(`Unknown field "${tokens[0].value}"`, line, tokens[0].column);
|
|
3720
4674
|
}
|
|
3721
|
-
|
|
4675
|
+
if (spec.version === "2.1") {
|
|
4676
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, tokens[0].value, {
|
|
4677
|
+
line,
|
|
4678
|
+
column: tokens[0].column
|
|
4679
|
+
});
|
|
4680
|
+
}
|
|
4681
|
+
const field = {
|
|
3722
4682
|
type: "field",
|
|
3723
4683
|
key: tokens[0].value,
|
|
3724
4684
|
values: tokens.slice(1).map((token) => token.value),
|
|
3725
4685
|
location: { line, column: tokens[0].column }
|
|
3726
4686
|
};
|
|
4687
|
+
validateDraftObjectFieldCompatibility([field], objectType);
|
|
4688
|
+
return field;
|
|
3727
4689
|
}
|
|
3728
|
-
function
|
|
4690
|
+
function parseInfoLikeEntry(tokens, line, errorMessage) {
|
|
3729
4691
|
if (tokens.length < 2) {
|
|
3730
|
-
throw new WorldOrbitError(
|
|
4692
|
+
throw new WorldOrbitError(errorMessage, line, tokens[0]?.column ?? 1);
|
|
3731
4693
|
}
|
|
3732
4694
|
return {
|
|
3733
4695
|
type: "info-entry",
|
|
@@ -3736,23 +4698,356 @@ var WorldOrbit = (() => {
|
|
|
3736
4698
|
location: { line, column: tokens[0].column }
|
|
3737
4699
|
};
|
|
3738
4700
|
}
|
|
3739
|
-
function
|
|
3740
|
-
|
|
4701
|
+
function normalizeDraftObject(node, sourceSchemaVersion, diagnostics) {
|
|
4702
|
+
const fieldMap = collectDraftFields(node.fields);
|
|
4703
|
+
const placement = extractDraftPlacement(node.objectType, fieldMap);
|
|
4704
|
+
const properties = normalizeDraftProperties(node.objectType, fieldMap);
|
|
4705
|
+
const groups = parseOptionalTokenList(fieldMap.get("groups")?.[0]);
|
|
4706
|
+
const epoch = parseOptionalJoinedValue(fieldMap.get("epoch")?.[0]);
|
|
4707
|
+
const referencePlane = parseOptionalJoinedValue(fieldMap.get("referencePlane")?.[0]);
|
|
4708
|
+
const tidalLock = fieldMap.has("tidalLock") ? parseAtlasBoolean(singleFieldValue2(fieldMap.get("tidalLock")[0]), "tidalLock", fieldMap.get("tidalLock")[0].location) : void 0;
|
|
4709
|
+
const resonance = fieldMap.has("resonance") ? parseResonanceField(fieldMap.get("resonance")[0]) : void 0;
|
|
4710
|
+
const renderHints = extractRenderHints(fieldMap);
|
|
4711
|
+
const deriveRules = fieldMap.get("derive")?.map((field) => parseDeriveField(field));
|
|
4712
|
+
const validationRules = fieldMap.get("validate")?.map((field) => ({
|
|
4713
|
+
rule: singleFieldValue2(field)
|
|
4714
|
+
}));
|
|
4715
|
+
const lockedFields = fieldMap.has("locked") ? [...new Set(fieldMap.get("locked").flatMap((field) => field.values))] : void 0;
|
|
4716
|
+
const tolerances = fieldMap.get("tolerance")?.map((field) => parseToleranceField(field));
|
|
4717
|
+
const typedBlocks = normalizeTypedBlocks(node.typedBlockEntries);
|
|
4718
|
+
const info2 = normalizeInfoEntries(node.infoEntries, "info");
|
|
4719
|
+
const object = {
|
|
4720
|
+
type: node.objectType,
|
|
4721
|
+
id: node.id,
|
|
4722
|
+
properties,
|
|
4723
|
+
placement,
|
|
4724
|
+
info: info2
|
|
4725
|
+
};
|
|
4726
|
+
if (groups.length > 0)
|
|
4727
|
+
object.groups = groups;
|
|
4728
|
+
if (epoch)
|
|
4729
|
+
object.epoch = epoch;
|
|
4730
|
+
if (referencePlane)
|
|
4731
|
+
object.referencePlane = referencePlane;
|
|
4732
|
+
if (tidalLock !== void 0)
|
|
4733
|
+
object.tidalLock = tidalLock;
|
|
4734
|
+
if (resonance)
|
|
4735
|
+
object.resonance = resonance;
|
|
4736
|
+
if (renderHints)
|
|
4737
|
+
object.renderHints = renderHints;
|
|
4738
|
+
if (deriveRules?.length)
|
|
4739
|
+
object.deriveRules = deriveRules;
|
|
4740
|
+
if (validationRules?.length)
|
|
4741
|
+
object.validationRules = validationRules;
|
|
4742
|
+
if (lockedFields?.length)
|
|
4743
|
+
object.lockedFields = lockedFields;
|
|
4744
|
+
if (tolerances?.length)
|
|
4745
|
+
object.tolerances = tolerances;
|
|
4746
|
+
if (typedBlocks && Object.keys(typedBlocks).length > 0)
|
|
4747
|
+
object.typedBlocks = typedBlocks;
|
|
4748
|
+
if (sourceSchemaVersion !== "2.1") {
|
|
4749
|
+
if (object.groups || object.epoch || object.referencePlane || object.tidalLock !== void 0 || object.resonance || object.renderHints || object.deriveRules?.length || object.validationRules?.length || object.lockedFields?.length || object.tolerances?.length || object.typedBlocks) {
|
|
4750
|
+
warnIfSchema21Feature(sourceSchemaVersion, diagnostics, node.id, node.location);
|
|
4751
|
+
}
|
|
4752
|
+
}
|
|
4753
|
+
return object;
|
|
4754
|
+
}
|
|
4755
|
+
function collectDraftFields(fields) {
|
|
4756
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
4757
|
+
for (const field of fields) {
|
|
4758
|
+
const spec = getDraftObjectFieldSpec(field.key);
|
|
4759
|
+
if (!spec) {
|
|
4760
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${field.key}"`, field.location);
|
|
4761
|
+
}
|
|
4762
|
+
if (!spec.allowRepeat && grouped.has(field.key)) {
|
|
4763
|
+
throw WorldOrbitError.fromLocation(`Duplicate field "${field.key}"`, field.location);
|
|
4764
|
+
}
|
|
4765
|
+
const existing = grouped.get(field.key) ?? [];
|
|
4766
|
+
existing.push(field);
|
|
4767
|
+
grouped.set(field.key, existing);
|
|
4768
|
+
}
|
|
4769
|
+
return grouped;
|
|
3741
4770
|
}
|
|
3742
|
-
function
|
|
3743
|
-
|
|
4771
|
+
function extractDraftPlacement(objectType, fieldMap) {
|
|
4772
|
+
const orbitField = fieldMap.get("orbit")?.[0];
|
|
4773
|
+
const atField = fieldMap.get("at")?.[0];
|
|
4774
|
+
const surfaceField = fieldMap.get("surface")?.[0];
|
|
4775
|
+
const freeField = fieldMap.get("free")?.[0];
|
|
4776
|
+
const count = [orbitField, atField, surfaceField, freeField].filter(Boolean).length;
|
|
4777
|
+
if (count > 1) {
|
|
4778
|
+
const conflictingField = orbitField ?? atField ?? surfaceField ?? freeField;
|
|
4779
|
+
throw WorldOrbitError.fromLocation("Object has multiple placement modes", conflictingField?.location);
|
|
4780
|
+
}
|
|
4781
|
+
if (orbitField) {
|
|
4782
|
+
return {
|
|
4783
|
+
mode: "orbit",
|
|
4784
|
+
target: singleFieldValue2(orbitField),
|
|
4785
|
+
distance: parseOptionalUnitField(fieldMap.get("distance")?.[0], "distance"),
|
|
4786
|
+
semiMajor: parseOptionalUnitField(fieldMap.get("semiMajor")?.[0], "semiMajor"),
|
|
4787
|
+
eccentricity: parseOptionalNumberField(fieldMap.get("eccentricity")?.[0], "eccentricity"),
|
|
4788
|
+
period: parseOptionalUnitField(fieldMap.get("period")?.[0], "period"),
|
|
4789
|
+
angle: parseOptionalUnitField(fieldMap.get("angle")?.[0], "angle"),
|
|
4790
|
+
inclination: parseOptionalUnitField(fieldMap.get("inclination")?.[0], "inclination"),
|
|
4791
|
+
phase: parseOptionalUnitField(fieldMap.get("phase")?.[0], "phase")
|
|
4792
|
+
};
|
|
4793
|
+
}
|
|
4794
|
+
if (atField) {
|
|
4795
|
+
const target = singleFieldValue2(atField);
|
|
4796
|
+
return {
|
|
4797
|
+
mode: "at",
|
|
4798
|
+
target,
|
|
4799
|
+
reference: parseAtlasAtReference(target, atField.location)
|
|
4800
|
+
};
|
|
4801
|
+
}
|
|
4802
|
+
if (surfaceField) {
|
|
4803
|
+
return {
|
|
4804
|
+
mode: "surface",
|
|
4805
|
+
target: singleFieldValue2(surfaceField)
|
|
4806
|
+
};
|
|
4807
|
+
}
|
|
4808
|
+
if (freeField) {
|
|
4809
|
+
const raw = singleFieldValue2(freeField);
|
|
4810
|
+
const distance = tryParseAtlasUnitValue(raw);
|
|
4811
|
+
return {
|
|
4812
|
+
mode: "free",
|
|
4813
|
+
distance: distance ?? void 0,
|
|
4814
|
+
descriptor: distance ? void 0 : raw
|
|
4815
|
+
};
|
|
4816
|
+
}
|
|
4817
|
+
return null;
|
|
4818
|
+
}
|
|
4819
|
+
function normalizeDraftProperties(objectType, fieldMap) {
|
|
4820
|
+
const properties = {};
|
|
4821
|
+
for (const [key, fields] of fieldMap.entries()) {
|
|
4822
|
+
const field = fields[0];
|
|
4823
|
+
const spec = getDraftObjectFieldSpec(key);
|
|
4824
|
+
if (!field || !spec?.legacySchema || spec.legacySchema.placement) {
|
|
4825
|
+
continue;
|
|
4826
|
+
}
|
|
4827
|
+
ensureAtlasFieldSupported(key, objectType, field.location);
|
|
4828
|
+
properties[key] = normalizeLegacyScalarValue(key, field.values, field.location);
|
|
4829
|
+
}
|
|
4830
|
+
return properties;
|
|
4831
|
+
}
|
|
4832
|
+
function normalizeInfoEntries(entries, label) {
|
|
4833
|
+
const normalized = {};
|
|
4834
|
+
for (const entry of entries) {
|
|
4835
|
+
if (entry.key in normalized) {
|
|
4836
|
+
throw WorldOrbitError.fromLocation(`Duplicate ${label} key "${entry.key}"`, entry.location);
|
|
4837
|
+
}
|
|
4838
|
+
normalized[entry.key] = entry.value;
|
|
4839
|
+
}
|
|
4840
|
+
return normalized;
|
|
4841
|
+
}
|
|
4842
|
+
function normalizeTypedBlocks(typedBlockEntries) {
|
|
4843
|
+
const typedBlocks = {};
|
|
4844
|
+
for (const blockName of Object.keys(typedBlockEntries)) {
|
|
4845
|
+
const entries = typedBlockEntries[blockName];
|
|
4846
|
+
if (entries?.length) {
|
|
4847
|
+
typedBlocks[blockName] = normalizeInfoEntries(entries, blockName);
|
|
4848
|
+
}
|
|
4849
|
+
}
|
|
4850
|
+
return typedBlocks;
|
|
4851
|
+
}
|
|
4852
|
+
function extractRenderHints(fieldMap) {
|
|
4853
|
+
const renderHints = {};
|
|
4854
|
+
const renderLabelField = fieldMap.get("renderLabel")?.[0];
|
|
4855
|
+
const renderOrbitField = fieldMap.get("renderOrbit")?.[0];
|
|
4856
|
+
const renderPriorityField = fieldMap.get("renderPriority")?.[0];
|
|
4857
|
+
if (renderLabelField) {
|
|
4858
|
+
renderHints.renderLabel = parseAtlasBoolean(singleFieldValue2(renderLabelField), "renderLabel", renderLabelField.location);
|
|
4859
|
+
}
|
|
4860
|
+
if (renderOrbitField) {
|
|
4861
|
+
renderHints.renderOrbit = parseAtlasBoolean(singleFieldValue2(renderOrbitField), "renderOrbit", renderOrbitField.location);
|
|
4862
|
+
}
|
|
4863
|
+
if (renderPriorityField) {
|
|
4864
|
+
renderHints.renderPriority = parseAtlasNumber(singleFieldValue2(renderPriorityField), "renderPriority", renderPriorityField.location);
|
|
4865
|
+
}
|
|
4866
|
+
return Object.keys(renderHints).length > 0 ? renderHints : void 0;
|
|
4867
|
+
}
|
|
4868
|
+
function parseResonanceField(field) {
|
|
4869
|
+
if (field.values.length !== 2) {
|
|
4870
|
+
throw WorldOrbitError.fromLocation('Field "resonance" expects "<targetObjectId> <ratio>"', field.location);
|
|
4871
|
+
}
|
|
4872
|
+
const ratio = field.values[1];
|
|
4873
|
+
if (!/^\d+:\d+$/.test(ratio)) {
|
|
4874
|
+
throw WorldOrbitError.fromLocation(`Invalid resonance ratio "${ratio}"`, field.location);
|
|
4875
|
+
}
|
|
4876
|
+
return {
|
|
4877
|
+
targetObjectId: field.values[0],
|
|
4878
|
+
ratio
|
|
4879
|
+
};
|
|
4880
|
+
}
|
|
4881
|
+
function parseDeriveField(field) {
|
|
4882
|
+
if (field.values.length !== 2) {
|
|
4883
|
+
throw WorldOrbitError.fromLocation('Field "derive" expects "<field> <strategy>"', field.location);
|
|
4884
|
+
}
|
|
4885
|
+
return {
|
|
4886
|
+
field: field.values[0],
|
|
4887
|
+
strategy: field.values[1]
|
|
4888
|
+
};
|
|
4889
|
+
}
|
|
4890
|
+
function parseToleranceField(field) {
|
|
4891
|
+
if (field.values.length !== 2) {
|
|
4892
|
+
throw WorldOrbitError.fromLocation('Field "tolerance" expects "<field> <value>"', field.location);
|
|
4893
|
+
}
|
|
4894
|
+
const rawValue = field.values[1];
|
|
4895
|
+
const unitValue = tryParseAtlasUnitValue(rawValue);
|
|
4896
|
+
const numericValue2 = Number(rawValue);
|
|
4897
|
+
return {
|
|
4898
|
+
field: field.values[0],
|
|
4899
|
+
value: unitValue ?? (Number.isFinite(numericValue2) ? numericValue2 : rawValue)
|
|
4900
|
+
};
|
|
4901
|
+
}
|
|
4902
|
+
function parseOptionalTokenList(field) {
|
|
4903
|
+
return field ? [...new Set(field.values)] : [];
|
|
4904
|
+
}
|
|
4905
|
+
function parseOptionalJoinedValue(field) {
|
|
4906
|
+
if (!field) {
|
|
4907
|
+
return null;
|
|
4908
|
+
}
|
|
4909
|
+
return field.values.join(" ").trim() || null;
|
|
4910
|
+
}
|
|
4911
|
+
function parseOptionalUnitField(field, key) {
|
|
4912
|
+
return field ? parseAtlasUnitValue(singleFieldValue2(field), field.location, key) : void 0;
|
|
4913
|
+
}
|
|
4914
|
+
function parseOptionalNumberField(field, key) {
|
|
4915
|
+
return field ? parseAtlasNumber(singleFieldValue2(field), key, field.location) : void 0;
|
|
4916
|
+
}
|
|
4917
|
+
function singleFieldValue2(field) {
|
|
4918
|
+
return singleAtlasValue(field.values, field.key, field.location);
|
|
4919
|
+
}
|
|
4920
|
+
function getDraftObjectFieldSpec(key) {
|
|
4921
|
+
return DRAFT_OBJECT_FIELD_SPECS.get(key);
|
|
4922
|
+
}
|
|
4923
|
+
function validateDraftObjectFieldCompatibility(fields, objectType) {
|
|
4924
|
+
for (const field of fields) {
|
|
4925
|
+
const spec = getDraftObjectFieldSpec(field.key);
|
|
4926
|
+
if (!spec) {
|
|
4927
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${field.key}"`, field.location);
|
|
4928
|
+
}
|
|
4929
|
+
if (spec.legacySchema) {
|
|
4930
|
+
ensureAtlasFieldSupported(field.key, objectType, field.location);
|
|
4931
|
+
continue;
|
|
4932
|
+
}
|
|
4933
|
+
if ((field.key === "renderLabel" || field.key === "renderOrbit" || field.key === "tidalLock") && field.values.length !== 1) {
|
|
4934
|
+
throw WorldOrbitError.fromLocation(`Field "${field.key}" expects exactly one value`, field.location);
|
|
4935
|
+
}
|
|
4936
|
+
}
|
|
4937
|
+
}
|
|
4938
|
+
function warnIfSchema21Feature(sourceSchemaVersion, diagnostics, featureName, location) {
|
|
4939
|
+
if (sourceSchemaVersion === "2.1") {
|
|
4940
|
+
return;
|
|
4941
|
+
}
|
|
4942
|
+
diagnostics.push({
|
|
4943
|
+
code: "parse.schema21.featureCompatibility",
|
|
4944
|
+
severity: "warning",
|
|
4945
|
+
source: "parse",
|
|
4946
|
+
message: `Feature "${featureName}" requires schema 2.1; parsed in compatibility mode because the document header is "schema ${sourceSchemaVersion}".`,
|
|
4947
|
+
line: location.line,
|
|
4948
|
+
column: location.column
|
|
4949
|
+
});
|
|
4950
|
+
}
|
|
4951
|
+
function preprocessAtlasSource(source) {
|
|
4952
|
+
const chars = [...source];
|
|
4953
|
+
const comments = [];
|
|
4954
|
+
let inString = false;
|
|
4955
|
+
let inBlockComment = false;
|
|
4956
|
+
let blockCommentStart = null;
|
|
4957
|
+
let line = 1;
|
|
4958
|
+
let column = 1;
|
|
4959
|
+
for (let index = 0; index < chars.length; index++) {
|
|
4960
|
+
const ch = chars[index];
|
|
4961
|
+
const next = chars[index + 1];
|
|
4962
|
+
if (inBlockComment) {
|
|
4963
|
+
if (ch === "*" && next === "/") {
|
|
4964
|
+
chars[index] = " ";
|
|
4965
|
+
chars[index + 1] = " ";
|
|
4966
|
+
inBlockComment = false;
|
|
4967
|
+
blockCommentStart = null;
|
|
4968
|
+
index++;
|
|
4969
|
+
column += 2;
|
|
4970
|
+
continue;
|
|
4971
|
+
}
|
|
4972
|
+
if (ch !== "\n" && ch !== "\r") {
|
|
4973
|
+
chars[index] = " ";
|
|
4974
|
+
}
|
|
4975
|
+
if (ch === "\n") {
|
|
4976
|
+
line++;
|
|
4977
|
+
column = 1;
|
|
4978
|
+
} else {
|
|
4979
|
+
column++;
|
|
4980
|
+
}
|
|
4981
|
+
continue;
|
|
4982
|
+
}
|
|
4983
|
+
if (!inString && ch === "/" && next === "*") {
|
|
4984
|
+
comments.push({ kind: "block", line, column });
|
|
4985
|
+
chars[index] = " ";
|
|
4986
|
+
chars[index + 1] = " ";
|
|
4987
|
+
inBlockComment = true;
|
|
4988
|
+
blockCommentStart = { line, column };
|
|
4989
|
+
index++;
|
|
4990
|
+
column += 2;
|
|
4991
|
+
continue;
|
|
4992
|
+
}
|
|
4993
|
+
if (!inString && ch === "#" && !isHexColorLiteral(chars, index)) {
|
|
4994
|
+
comments.push({ kind: "line", line, column });
|
|
4995
|
+
chars[index] = " ";
|
|
4996
|
+
let inner = index + 1;
|
|
4997
|
+
while (inner < chars.length && chars[inner] !== "\n" && chars[inner] !== "\r") {
|
|
4998
|
+
chars[inner] = " ";
|
|
4999
|
+
inner++;
|
|
5000
|
+
}
|
|
5001
|
+
column += inner - index;
|
|
5002
|
+
index = inner - 1;
|
|
5003
|
+
continue;
|
|
5004
|
+
}
|
|
5005
|
+
if (ch === '"' && chars[index - 1] !== "\\") {
|
|
5006
|
+
inString = !inString;
|
|
5007
|
+
}
|
|
5008
|
+
if (ch === "\n") {
|
|
5009
|
+
line++;
|
|
5010
|
+
column = 1;
|
|
5011
|
+
} else {
|
|
5012
|
+
column++;
|
|
5013
|
+
}
|
|
5014
|
+
}
|
|
5015
|
+
if (inBlockComment) {
|
|
5016
|
+
throw WorldOrbitError.fromLocation("Unclosed block comment", blockCommentStart ?? void 0);
|
|
5017
|
+
}
|
|
5018
|
+
return {
|
|
5019
|
+
source: chars.join(""),
|
|
5020
|
+
comments
|
|
5021
|
+
};
|
|
5022
|
+
}
|
|
5023
|
+
function isHexColorLiteral(chars, start) {
|
|
5024
|
+
let index = start + 1;
|
|
5025
|
+
let length = 0;
|
|
5026
|
+
while (index < chars.length && /[0-9a-f]/i.test(chars[index] ?? "")) {
|
|
5027
|
+
index++;
|
|
5028
|
+
length++;
|
|
5029
|
+
}
|
|
5030
|
+
if (![3, 4, 6, 8].includes(length)) {
|
|
5031
|
+
return false;
|
|
5032
|
+
}
|
|
5033
|
+
const next = chars[index];
|
|
5034
|
+
return next === void 0 || next === " " || next === " " || next === "\r" || next === "\n";
|
|
3744
5035
|
}
|
|
3745
5036
|
|
|
3746
5037
|
// packages/core/dist/atlas-edit.js
|
|
3747
|
-
function createEmptyAtlasDocument(systemId = "WorldOrbit") {
|
|
5038
|
+
function createEmptyAtlasDocument(systemId = "WorldOrbit", version = "2.0") {
|
|
3748
5039
|
return {
|
|
3749
5040
|
format: "worldorbit",
|
|
3750
|
-
version
|
|
5041
|
+
version,
|
|
5042
|
+
schemaVersion: version,
|
|
3751
5043
|
sourceVersion: "1.0",
|
|
3752
5044
|
system: {
|
|
3753
5045
|
type: "system",
|
|
3754
5046
|
id: systemId,
|
|
3755
5047
|
title: systemId,
|
|
5048
|
+
description: null,
|
|
5049
|
+
epoch: null,
|
|
5050
|
+
referencePlane: null,
|
|
3756
5051
|
defaults: {
|
|
3757
5052
|
view: "topdown",
|
|
3758
5053
|
scale: null,
|
|
@@ -3764,6 +5059,8 @@ var WorldOrbit = (() => {
|
|
|
3764
5059
|
viewpoints: [],
|
|
3765
5060
|
annotations: []
|
|
3766
5061
|
},
|
|
5062
|
+
groups: [],
|
|
5063
|
+
relations: [],
|
|
3767
5064
|
objects: [],
|
|
3768
5065
|
diagnostics: []
|
|
3769
5066
|
};
|
|
@@ -3777,14 +5074,20 @@ var WorldOrbit = (() => {
|
|
|
3777
5074
|
for (const key of Object.keys(document2.system.atlasMetadata).sort()) {
|
|
3778
5075
|
paths.push({ kind: "metadata", key });
|
|
3779
5076
|
}
|
|
3780
|
-
for (const viewpoint of [...document2.system.viewpoints].sort(
|
|
5077
|
+
for (const viewpoint of [...document2.system.viewpoints].sort(compareIdLike2)) {
|
|
3781
5078
|
paths.push({ kind: "viewpoint", id: viewpoint.id });
|
|
3782
5079
|
}
|
|
3783
|
-
for (const annotation of [...document2.system.annotations].sort(
|
|
5080
|
+
for (const annotation of [...document2.system.annotations].sort(compareIdLike2)) {
|
|
3784
5081
|
paths.push({ kind: "annotation", id: annotation.id });
|
|
3785
5082
|
}
|
|
3786
5083
|
}
|
|
3787
|
-
for (const
|
|
5084
|
+
for (const group of [...document2.groups].sort(compareIdLike2)) {
|
|
5085
|
+
paths.push({ kind: "group", id: group.id });
|
|
5086
|
+
}
|
|
5087
|
+
for (const relation of [...document2.relations].sort(compareIdLike2)) {
|
|
5088
|
+
paths.push({ kind: "relation", id: relation.id });
|
|
5089
|
+
}
|
|
5090
|
+
for (const object of [...document2.objects].sort(compareIdLike2)) {
|
|
3788
5091
|
paths.push({ kind: "object", id: object.id });
|
|
3789
5092
|
}
|
|
3790
5093
|
return paths;
|
|
@@ -3797,12 +5100,16 @@ var WorldOrbit = (() => {
|
|
|
3797
5100
|
return document2.system?.defaults ?? null;
|
|
3798
5101
|
case "metadata":
|
|
3799
5102
|
return path.key ? document2.system?.atlasMetadata[path.key] ?? null : null;
|
|
5103
|
+
case "group":
|
|
5104
|
+
return path.id ? findGroup(document2, path.id) : null;
|
|
3800
5105
|
case "object":
|
|
3801
5106
|
return path.id ? findObject(document2, path.id) : null;
|
|
3802
5107
|
case "viewpoint":
|
|
3803
5108
|
return path.id ? findViewpoint(document2.system, path.id) : null;
|
|
3804
5109
|
case "annotation":
|
|
3805
5110
|
return path.id ? findAnnotation(document2.system, path.id) : null;
|
|
5111
|
+
case "relation":
|
|
5112
|
+
return path.id ? findRelation(document2, path.id) : null;
|
|
3806
5113
|
}
|
|
3807
5114
|
}
|
|
3808
5115
|
function upsertAtlasDocumentNode(document2, path, value) {
|
|
@@ -3828,6 +5135,12 @@ var WorldOrbit = (() => {
|
|
|
3828
5135
|
system.atlasMetadata[path.key] = String(value);
|
|
3829
5136
|
}
|
|
3830
5137
|
return next;
|
|
5138
|
+
case "group":
|
|
5139
|
+
if (!path.id) {
|
|
5140
|
+
throw new Error('Group updates require an "id" value.');
|
|
5141
|
+
}
|
|
5142
|
+
upsertById(next.groups, value);
|
|
5143
|
+
return next;
|
|
3831
5144
|
case "object":
|
|
3832
5145
|
if (!path.id) {
|
|
3833
5146
|
throw new Error('Object updates require an "id" value.');
|
|
@@ -3846,6 +5159,12 @@ var WorldOrbit = (() => {
|
|
|
3846
5159
|
}
|
|
3847
5160
|
upsertById(system.annotations, value);
|
|
3848
5161
|
return next;
|
|
5162
|
+
case "relation":
|
|
5163
|
+
if (!path.id) {
|
|
5164
|
+
throw new Error('Relation updates require an "id" value.');
|
|
5165
|
+
}
|
|
5166
|
+
upsertById(next.relations, value);
|
|
5167
|
+
return next;
|
|
3849
5168
|
}
|
|
3850
5169
|
}
|
|
3851
5170
|
function updateAtlasDocumentNode(document2, path, updater) {
|
|
@@ -3865,6 +5184,11 @@ var WorldOrbit = (() => {
|
|
|
3865
5184
|
next.objects = next.objects.filter((object) => object.id !== path.id);
|
|
3866
5185
|
}
|
|
3867
5186
|
return next;
|
|
5187
|
+
case "group":
|
|
5188
|
+
if (path.id) {
|
|
5189
|
+
next.groups = next.groups.filter((group) => group.id !== path.id);
|
|
5190
|
+
}
|
|
5191
|
+
return next;
|
|
3868
5192
|
case "viewpoint":
|
|
3869
5193
|
if (path.id) {
|
|
3870
5194
|
system.viewpoints = system.viewpoints.filter((viewpoint) => viewpoint.id !== path.id);
|
|
@@ -3875,6 +5199,11 @@ var WorldOrbit = (() => {
|
|
|
3875
5199
|
system.annotations = system.annotations.filter((annotation) => annotation.id !== path.id);
|
|
3876
5200
|
}
|
|
3877
5201
|
return next;
|
|
5202
|
+
case "relation":
|
|
5203
|
+
if (path.id) {
|
|
5204
|
+
next.relations = next.relations.filter((relation) => relation.id !== path.id);
|
|
5205
|
+
}
|
|
5206
|
+
return next;
|
|
3878
5207
|
default:
|
|
3879
5208
|
return next;
|
|
3880
5209
|
}
|
|
@@ -3892,6 +5221,15 @@ var WorldOrbit = (() => {
|
|
|
3892
5221
|
id: diagnostic.objectId
|
|
3893
5222
|
};
|
|
3894
5223
|
}
|
|
5224
|
+
if (diagnostic.field?.startsWith("group.")) {
|
|
5225
|
+
const parts = diagnostic.field.split(".");
|
|
5226
|
+
if (parts[1] && findGroup(document2, parts[1])) {
|
|
5227
|
+
return {
|
|
5228
|
+
kind: "group",
|
|
5229
|
+
id: parts[1]
|
|
5230
|
+
};
|
|
5231
|
+
}
|
|
5232
|
+
}
|
|
3895
5233
|
if (diagnostic.field?.startsWith("viewpoint.")) {
|
|
3896
5234
|
const parts = diagnostic.field.split(".");
|
|
3897
5235
|
if (parts[1] && findViewpoint(document2.system, parts[1])) {
|
|
@@ -3910,6 +5248,15 @@ var WorldOrbit = (() => {
|
|
|
3910
5248
|
};
|
|
3911
5249
|
}
|
|
3912
5250
|
}
|
|
5251
|
+
if (diagnostic.field?.startsWith("relation.")) {
|
|
5252
|
+
const parts = diagnostic.field.split(".");
|
|
5253
|
+
if (parts[1] && findRelation(document2, parts[1])) {
|
|
5254
|
+
return {
|
|
5255
|
+
kind: "relation",
|
|
5256
|
+
id: parts[1]
|
|
5257
|
+
};
|
|
5258
|
+
}
|
|
5259
|
+
}
|
|
3913
5260
|
if (diagnostic.field && diagnostic.field in ensureSystem(document2).atlasMetadata) {
|
|
3914
5261
|
return {
|
|
3915
5262
|
kind: "metadata",
|
|
@@ -3919,9 +5266,11 @@ var WorldOrbit = (() => {
|
|
|
3919
5266
|
return null;
|
|
3920
5267
|
}
|
|
3921
5268
|
function validateAtlasDocumentWithDiagnostics(document2) {
|
|
3922
|
-
const
|
|
3923
|
-
|
|
3924
|
-
|
|
5269
|
+
const diagnostics = [
|
|
5270
|
+
...document2.diagnostics,
|
|
5271
|
+
...collectAtlasDiagnostics(document2, document2.version)
|
|
5272
|
+
];
|
|
5273
|
+
return resolveAtlasDiagnostics(document2, diagnostics);
|
|
3925
5274
|
}
|
|
3926
5275
|
function ensureSystem(document2) {
|
|
3927
5276
|
if (document2.system) {
|
|
@@ -3933,6 +5282,12 @@ var WorldOrbit = (() => {
|
|
|
3933
5282
|
function findObject(document2, objectId) {
|
|
3934
5283
|
return document2.objects.find((object) => object.id === objectId) ?? null;
|
|
3935
5284
|
}
|
|
5285
|
+
function findGroup(document2, groupId) {
|
|
5286
|
+
return document2.groups.find((group) => group.id === groupId) ?? null;
|
|
5287
|
+
}
|
|
5288
|
+
function findRelation(document2, relationId) {
|
|
5289
|
+
return document2.relations.find((relation) => relation.id === relationId) ?? null;
|
|
5290
|
+
}
|
|
3936
5291
|
function findViewpoint(system, viewpointId) {
|
|
3937
5292
|
return system?.viewpoints.find((viewpoint) => viewpoint.id === viewpointId) ?? null;
|
|
3938
5293
|
}
|
|
@@ -3943,20 +5298,21 @@ var WorldOrbit = (() => {
|
|
|
3943
5298
|
const index = items.findIndex((item) => item.id === value.id);
|
|
3944
5299
|
if (index === -1) {
|
|
3945
5300
|
items.push(value);
|
|
3946
|
-
items.sort(
|
|
5301
|
+
items.sort(compareIdLike2);
|
|
3947
5302
|
return;
|
|
3948
5303
|
}
|
|
3949
5304
|
items[index] = value;
|
|
3950
5305
|
}
|
|
3951
|
-
function
|
|
5306
|
+
function compareIdLike2(left, right) {
|
|
3952
5307
|
return left.id.localeCompare(right.id);
|
|
3953
5308
|
}
|
|
3954
5309
|
|
|
3955
5310
|
// packages/core/dist/load.js
|
|
3956
|
-
var ATLAS_SCHEMA_PATTERN = /^schema\s+2(?:\.0)?$/i;
|
|
5311
|
+
var ATLAS_SCHEMA_PATTERN = /^schema\s+2(?:\.0|\.1)?$/i;
|
|
5312
|
+
var ATLAS_SCHEMA_21_PATTERN = /^schema\s+2\.1$/i;
|
|
3957
5313
|
var LEGACY_DRAFT_SCHEMA_PATTERN = /^schema\s+2\.0-draft$/i;
|
|
3958
5314
|
function detectWorldOrbitSchemaVersion(source) {
|
|
3959
|
-
for (const line of source.split(/\r?\n/)) {
|
|
5315
|
+
for (const line of stripCommentsForSchemaDetection(source).split(/\r?\n/)) {
|
|
3960
5316
|
const trimmed = line.trim();
|
|
3961
5317
|
if (!trimmed) {
|
|
3962
5318
|
continue;
|
|
@@ -3964,6 +5320,9 @@ var WorldOrbit = (() => {
|
|
|
3964
5320
|
if (LEGACY_DRAFT_SCHEMA_PATTERN.test(trimmed)) {
|
|
3965
5321
|
return "2.0-draft";
|
|
3966
5322
|
}
|
|
5323
|
+
if (ATLAS_SCHEMA_21_PATTERN.test(trimmed)) {
|
|
5324
|
+
return "2.1";
|
|
5325
|
+
}
|
|
3967
5326
|
if (ATLAS_SCHEMA_PATTERN.test(trimmed)) {
|
|
3968
5327
|
return "2.0";
|
|
3969
5328
|
}
|
|
@@ -3971,6 +5330,49 @@ var WorldOrbit = (() => {
|
|
|
3971
5330
|
}
|
|
3972
5331
|
return "1.0";
|
|
3973
5332
|
}
|
|
5333
|
+
function stripCommentsForSchemaDetection(source) {
|
|
5334
|
+
const chars = [...source];
|
|
5335
|
+
let inString = false;
|
|
5336
|
+
let inBlockComment = false;
|
|
5337
|
+
for (let index = 0; index < chars.length; index++) {
|
|
5338
|
+
const ch = chars[index];
|
|
5339
|
+
const next = chars[index + 1];
|
|
5340
|
+
if (inBlockComment) {
|
|
5341
|
+
if (ch === "*" && next === "/") {
|
|
5342
|
+
chars[index] = " ";
|
|
5343
|
+
chars[index + 1] = " ";
|
|
5344
|
+
inBlockComment = false;
|
|
5345
|
+
index++;
|
|
5346
|
+
continue;
|
|
5347
|
+
}
|
|
5348
|
+
if (ch !== "\n" && ch !== "\r") {
|
|
5349
|
+
chars[index] = " ";
|
|
5350
|
+
}
|
|
5351
|
+
continue;
|
|
5352
|
+
}
|
|
5353
|
+
if (!inString && ch === "/" && next === "*") {
|
|
5354
|
+
chars[index] = " ";
|
|
5355
|
+
chars[index + 1] = " ";
|
|
5356
|
+
inBlockComment = true;
|
|
5357
|
+
index++;
|
|
5358
|
+
continue;
|
|
5359
|
+
}
|
|
5360
|
+
if (!inString && ch === "#") {
|
|
5361
|
+
chars[index] = " ";
|
|
5362
|
+
let inner = index + 1;
|
|
5363
|
+
while (inner < chars.length && chars[inner] !== "\n" && chars[inner] !== "\r") {
|
|
5364
|
+
chars[inner] = " ";
|
|
5365
|
+
inner++;
|
|
5366
|
+
}
|
|
5367
|
+
index = inner - 1;
|
|
5368
|
+
continue;
|
|
5369
|
+
}
|
|
5370
|
+
if (ch === '"' && chars[index - 1] !== "\\") {
|
|
5371
|
+
inString = !inString;
|
|
5372
|
+
}
|
|
5373
|
+
}
|
|
5374
|
+
return chars.join("");
|
|
5375
|
+
}
|
|
3974
5376
|
function loadWorldOrbitSource(source) {
|
|
3975
5377
|
const result = loadWorldOrbitSourceWithDiagnostics(source);
|
|
3976
5378
|
if (!result.ok || !result.value) {
|
|
@@ -3981,36 +5383,36 @@ var WorldOrbit = (() => {
|
|
|
3981
5383
|
}
|
|
3982
5384
|
function loadWorldOrbitSourceWithDiagnostics(source) {
|
|
3983
5385
|
const schemaVersion = detectWorldOrbitSchemaVersion(source);
|
|
3984
|
-
if (schemaVersion === "2.0" || schemaVersion === "2.0-draft") {
|
|
5386
|
+
if (schemaVersion === "2.0" || schemaVersion === "2.0-draft" || schemaVersion === "2.1") {
|
|
3985
5387
|
return loadAtlasSourceWithDiagnostics(source, schemaVersion);
|
|
3986
5388
|
}
|
|
3987
5389
|
let ast;
|
|
3988
5390
|
try {
|
|
3989
5391
|
ast = parseWorldOrbit(source);
|
|
3990
|
-
} catch (
|
|
5392
|
+
} catch (error2) {
|
|
3991
5393
|
return {
|
|
3992
5394
|
ok: false,
|
|
3993
5395
|
value: null,
|
|
3994
|
-
diagnostics: [diagnosticFromError(
|
|
5396
|
+
diagnostics: [diagnosticFromError(error2, "parse")]
|
|
3995
5397
|
};
|
|
3996
5398
|
}
|
|
3997
5399
|
let document2;
|
|
3998
5400
|
try {
|
|
3999
5401
|
document2 = normalizeDocument(ast);
|
|
4000
|
-
} catch (
|
|
5402
|
+
} catch (error2) {
|
|
4001
5403
|
return {
|
|
4002
5404
|
ok: false,
|
|
4003
5405
|
value: null,
|
|
4004
|
-
diagnostics: [diagnosticFromError(
|
|
5406
|
+
diagnostics: [diagnosticFromError(error2, "normalize")]
|
|
4005
5407
|
};
|
|
4006
5408
|
}
|
|
4007
5409
|
try {
|
|
4008
5410
|
validateDocument(document2);
|
|
4009
|
-
} catch (
|
|
5411
|
+
} catch (error2) {
|
|
4010
5412
|
return {
|
|
4011
5413
|
ok: false,
|
|
4012
5414
|
value: null,
|
|
4013
|
-
diagnostics: [diagnosticFromError(
|
|
5415
|
+
diagnostics: [diagnosticFromError(error2, "validate")]
|
|
4014
5416
|
};
|
|
4015
5417
|
}
|
|
4016
5418
|
return {
|
|
@@ -4030,30 +5432,29 @@ var WorldOrbit = (() => {
|
|
|
4030
5432
|
let atlasDocument;
|
|
4031
5433
|
try {
|
|
4032
5434
|
atlasDocument = parseWorldOrbitAtlas(source);
|
|
4033
|
-
} catch (
|
|
5435
|
+
} catch (error2) {
|
|
4034
5436
|
return {
|
|
4035
5437
|
ok: false,
|
|
4036
5438
|
value: null,
|
|
4037
|
-
diagnostics: [diagnosticFromError(
|
|
5439
|
+
diagnostics: [diagnosticFromError(error2, "parse", "load.atlas.failed")]
|
|
4038
5440
|
};
|
|
4039
5441
|
}
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
document2 = materializeAtlasDocument(atlasDocument);
|
|
4043
|
-
} catch (error) {
|
|
5442
|
+
const atlasDiagnostics = [...atlasDocument.diagnostics];
|
|
5443
|
+
if (atlasDiagnostics.some((diagnostic) => diagnostic.severity === "error")) {
|
|
4044
5444
|
return {
|
|
4045
5445
|
ok: false,
|
|
4046
5446
|
value: null,
|
|
4047
|
-
diagnostics:
|
|
5447
|
+
diagnostics: atlasDiagnostics
|
|
4048
5448
|
};
|
|
4049
5449
|
}
|
|
5450
|
+
let document2;
|
|
4050
5451
|
try {
|
|
4051
|
-
|
|
4052
|
-
} catch (
|
|
5452
|
+
document2 = materializeAtlasDocument(atlasDocument);
|
|
5453
|
+
} catch (error2) {
|
|
4053
5454
|
return {
|
|
4054
5455
|
ok: false,
|
|
4055
5456
|
value: null,
|
|
4056
|
-
diagnostics: [diagnosticFromError(
|
|
5457
|
+
diagnostics: [diagnosticFromError(error2, "normalize", "load.atlas.materialize.failed")]
|
|
4057
5458
|
};
|
|
4058
5459
|
}
|
|
4059
5460
|
const loaded = {
|
|
@@ -4062,12 +5463,12 @@ var WorldOrbit = (() => {
|
|
|
4062
5463
|
document: document2,
|
|
4063
5464
|
atlasDocument,
|
|
4064
5465
|
draftDocument: atlasDocument,
|
|
4065
|
-
diagnostics:
|
|
5466
|
+
diagnostics: atlasDiagnostics
|
|
4066
5467
|
};
|
|
4067
5468
|
return {
|
|
4068
5469
|
ok: true,
|
|
4069
5470
|
value: loaded,
|
|
4070
|
-
diagnostics:
|
|
5471
|
+
diagnostics: atlasDiagnostics
|
|
4071
5472
|
};
|
|
4072
5473
|
}
|
|
4073
5474
|
|
|
@@ -4138,6 +5539,7 @@ var WorldOrbit = (() => {
|
|
|
4138
5539
|
var DEFAULT_LAYERS = {
|
|
4139
5540
|
background: true,
|
|
4140
5541
|
guides: true,
|
|
5542
|
+
relations: true,
|
|
4141
5543
|
orbits: true,
|
|
4142
5544
|
objects: true,
|
|
4143
5545
|
labels: true,
|
|
@@ -4152,6 +5554,7 @@ var WorldOrbit = (() => {
|
|
|
4152
5554
|
backgroundGlow: "rgba(240, 180, 100, 0.18)",
|
|
4153
5555
|
panel: "rgba(7, 17, 27, 0.9)",
|
|
4154
5556
|
panelLine: "rgba(168, 207, 242, 0.18)",
|
|
5557
|
+
relation: "rgba(240, 180, 100, 0.42)",
|
|
4155
5558
|
orbit: "rgba(163, 209, 255, 0.24)",
|
|
4156
5559
|
orbitBand: "rgba(255, 190, 120, 0.28)",
|
|
4157
5560
|
guide: "rgba(255, 255, 255, 0.04)",
|
|
@@ -4174,6 +5577,7 @@ var WorldOrbit = (() => {
|
|
|
4174
5577
|
backgroundGlow: "rgba(120, 255, 215, 0.16)",
|
|
4175
5578
|
panel: "rgba(7, 20, 30, 0.9)",
|
|
4176
5579
|
panelLine: "rgba(120, 255, 215, 0.16)",
|
|
5580
|
+
relation: "rgba(156, 231, 255, 0.42)",
|
|
4177
5581
|
orbit: "rgba(120, 255, 215, 0.2)",
|
|
4178
5582
|
orbitBand: "rgba(137, 185, 255, 0.24)",
|
|
4179
5583
|
guide: "rgba(255, 255, 255, 0.035)",
|
|
@@ -4196,6 +5600,7 @@ var WorldOrbit = (() => {
|
|
|
4196
5600
|
backgroundGlow: "rgba(255, 127, 95, 0.18)",
|
|
4197
5601
|
panel: "rgba(24, 9, 13, 0.9)",
|
|
4198
5602
|
panelLine: "rgba(255, 166, 149, 0.16)",
|
|
5603
|
+
relation: "rgba(255, 178, 125, 0.42)",
|
|
4199
5604
|
orbit: "rgba(255, 188, 164, 0.22)",
|
|
4200
5605
|
orbitBand: "rgba(255, 214, 139, 0.24)",
|
|
4201
5606
|
guide: "rgba(255, 255, 255, 0.03)",
|
|
@@ -4348,6 +5753,7 @@ var WorldOrbit = (() => {
|
|
|
4348
5753
|
return {
|
|
4349
5754
|
background: viewpoint.layers.background,
|
|
4350
5755
|
guides: viewpoint.layers.guides,
|
|
5756
|
+
relations: viewpoint.layers.relations,
|
|
4351
5757
|
orbits: viewpoint.layers["orbits-front"] === void 0 && viewpoint.layers["orbits-back"] === void 0 ? void 0 : viewpoint.layers["orbits-front"] !== false || viewpoint.layers["orbits-back"] !== false,
|
|
4352
5758
|
objects: viewpoint.layers.objects,
|
|
4353
5759
|
labels: viewpoint.layers.labels,
|
|
@@ -4385,7 +5791,11 @@ var WorldOrbit = (() => {
|
|
|
4385
5791
|
return false;
|
|
4386
5792
|
}
|
|
4387
5793
|
if (filter.groupIds?.length && (!object.groupId || !filter.groupIds.includes(object.groupId))) {
|
|
4388
|
-
|
|
5794
|
+
const hasSemanticMatch = object.semanticGroupIds.length > 0 && filter.groupIds.some((groupId) => object.semanticGroupIds.includes(groupId));
|
|
5795
|
+
const hasLegacyMatch = Boolean(object.groupId && filter.groupIds.includes(object.groupId));
|
|
5796
|
+
if (!hasSemanticMatch && !hasLegacyMatch) {
|
|
5797
|
+
return false;
|
|
5798
|
+
}
|
|
4389
5799
|
}
|
|
4390
5800
|
if (filter.tags?.length) {
|
|
4391
5801
|
const objectTags = Array.isArray(object.object.properties.tags) ? object.object.properties.tags.filter((entry) => typeof entry === "string") : [];
|
|
@@ -4629,6 +6039,7 @@ var WorldOrbit = (() => {
|
|
|
4629
6039
|
const imageDefinitions = buildImageDefinitions(visibleObjects);
|
|
4630
6040
|
const orbitMarkup = layers.orbits ? renderOrbitLayer(scene, visibleObjectIds, layers.structures) : { back: "", front: "" };
|
|
4631
6041
|
const leaderMarkup = layers.guides ? scene.leaders.filter((leader) => !leader.hidden).filter((leader) => visibleObjectIds.has(leader.objectId)).filter((leader) => layers.structures || !isStructureLike(leader.object)).map((leader) => `<line class="wo-leader wo-leader-${leader.mode}" x1="${leader.x1}" y1="${leader.y1}" x2="${leader.x2}" y2="${leader.y2}" data-render-id="${escapeXml(leader.renderId)}" data-group-id="${escapeAttribute(leader.groupId ?? "")}" />`).join("") : "";
|
|
6042
|
+
const relationMarkup = layers.relations ? scene.relations.filter((relation) => !relation.hidden).filter((relation) => visibleObjectIds.has(relation.fromObjectId) && visibleObjectIds.has(relation.toObjectId)).map((relation) => `<line class="wo-relation" x1="${relation.x1}" y1="${relation.y1}" x2="${relation.x2}" y2="${relation.y2}" data-render-id="${escapeXml(relation.renderId)}" data-relation-id="${escapeAttribute(relation.relationId)}" />`).join("") : "";
|
|
4632
6043
|
const objectMarkup = layers.objects ? visibleObjects.map((object) => renderSceneObject(object, options.selectedObjectId ?? null, theme)).join("") : "";
|
|
4633
6044
|
const labelMarkup = layers.labels ? visibleLabels.map((label) => renderSceneLabel(scene, label, options.selectedObjectId ?? null)).join("") : "";
|
|
4634
6045
|
const metadataMarkup = layers.metadata ? `<text class="wo-title" x="56" y="64">${escapeXml(scene.title)}</text>
|
|
@@ -4663,6 +6074,7 @@ var WorldOrbit = (() => {
|
|
|
4663
6074
|
.wo-orbit-back { opacity: 0.38; stroke-dasharray: 8 6; }
|
|
4664
6075
|
.wo-orbit-front { opacity: 0.9; }
|
|
4665
6076
|
.wo-orbit-band { stroke: ${theme.orbitBand}; stroke-linecap: round; }
|
|
6077
|
+
.wo-relation { stroke: ${theme.relation}; stroke-width: 2; stroke-dasharray: 10 6; }
|
|
4666
6078
|
.wo-leader { stroke: ${theme.leader}; stroke-width: 1.5; stroke-dasharray: 6 5; }
|
|
4667
6079
|
.wo-label { fill: ${theme.ink}; font-family: ${theme.fontFamily}; font-weight: 600; letter-spacing: 0.02em; }
|
|
4668
6080
|
.wo-label-secondary { fill: ${theme.muted}; font-family: ${theme.fontFamily}; font-weight: 500; }
|
|
@@ -4696,6 +6108,7 @@ var WorldOrbit = (() => {
|
|
|
4696
6108
|
<g data-worldorbit-world-content="true">
|
|
4697
6109
|
${layers.orbits ? `<g data-layer-id="orbits-back">${orbitMarkup.back}</g>` : ""}
|
|
4698
6110
|
${layers.guides ? `<g data-layer-id="guides">${leaderMarkup}</g>` : ""}
|
|
6111
|
+
${layers.relations ? `<g data-layer-id="relations">${relationMarkup}</g>` : ""}
|
|
4699
6112
|
${layers.objects ? `<g data-layer-id="objects">${objectMarkup}</g>` : ""}
|
|
4700
6113
|
${layers.orbits ? `<g data-layer-id="orbits-front">${orbitMarkup.front}</g>` : ""}
|
|
4701
6114
|
${layers.labels ? `<g data-layer-id="labels">${labelMarkup}</g>` : ""}
|
|
@@ -5267,6 +6680,41 @@ var WorldOrbit = (() => {
|
|
|
5267
6680
|
});
|
|
5268
6681
|
}
|
|
5269
6682
|
const placement = details.object.placement;
|
|
6683
|
+
if (details.object.groups?.length) {
|
|
6684
|
+
fields.set("groups", {
|
|
6685
|
+
key: "groups",
|
|
6686
|
+
label: "Groups",
|
|
6687
|
+
value: details.object.groups.join(", ")
|
|
6688
|
+
});
|
|
6689
|
+
}
|
|
6690
|
+
if (details.object.epoch) {
|
|
6691
|
+
fields.set("epoch", {
|
|
6692
|
+
key: "epoch",
|
|
6693
|
+
label: "Epoch",
|
|
6694
|
+
value: details.object.epoch
|
|
6695
|
+
});
|
|
6696
|
+
}
|
|
6697
|
+
if (details.object.referencePlane) {
|
|
6698
|
+
fields.set("referencePlane", {
|
|
6699
|
+
key: "referencePlane",
|
|
6700
|
+
label: "Reference Plane",
|
|
6701
|
+
value: details.object.referencePlane
|
|
6702
|
+
});
|
|
6703
|
+
}
|
|
6704
|
+
if (details.object.tidalLock !== void 0) {
|
|
6705
|
+
fields.set("tidalLock", {
|
|
6706
|
+
key: "tidalLock",
|
|
6707
|
+
label: "Tidal Lock",
|
|
6708
|
+
value: details.object.tidalLock ? "true" : "false"
|
|
6709
|
+
});
|
|
6710
|
+
}
|
|
6711
|
+
if (details.object.resonance) {
|
|
6712
|
+
fields.set("resonance", {
|
|
6713
|
+
key: "resonance",
|
|
6714
|
+
label: "Resonance",
|
|
6715
|
+
value: `${details.object.resonance.targetObjectId} ${details.object.resonance.ratio}`
|
|
6716
|
+
});
|
|
6717
|
+
}
|
|
5270
6718
|
if (placement?.mode === "at") {
|
|
5271
6719
|
fields.set("placement", {
|
|
5272
6720
|
key: "placement",
|
|
@@ -5941,8 +7389,10 @@ var WorldOrbit = (() => {
|
|
|
5941
7389
|
renderObject,
|
|
5942
7390
|
label: scene.labels.find((label) => label.objectId === renderObject.objectId && !label.hidden) ?? null,
|
|
5943
7391
|
group: scene.groups.find((group) => group.renderId === renderObject.groupId) ?? null,
|
|
7392
|
+
semanticGroups: scene.semanticGroups.filter((group) => renderObject.semanticGroupIds.includes(group.id)),
|
|
5944
7393
|
orbit: scene.orbitVisuals.find((orbit) => orbit.objectId === renderObject.objectId && !orbit.hidden) ?? null,
|
|
5945
7394
|
relatedOrbits: scene.orbitVisuals.filter((orbit) => !orbit.hidden && (orbit.objectId === renderObject.objectId || renderObject.ancestorIds.includes(orbit.objectId) || renderObject.childIds.includes(orbit.objectId))),
|
|
7395
|
+
relations: scene.relations.filter((relation) => !relation.hidden && (relation.fromObjectId === renderObject.objectId || relation.toObjectId === renderObject.objectId)),
|
|
5946
7396
|
parent: getObjectById(renderObject.parentId),
|
|
5947
7397
|
children: renderObject.childIds.map((childId) => getObjectById(childId)).filter(Boolean),
|
|
5948
7398
|
ancestors: renderObject.ancestorIds.map((ancestorId) => getObjectById(ancestorId)).filter(Boolean),
|
|
@@ -6567,6 +8017,7 @@ var WorldOrbit = (() => {
|
|
|
6567
8017
|
const controls = {
|
|
6568
8018
|
search: options.controls?.search ?? true,
|
|
6569
8019
|
typeFilter: options.controls?.typeFilter ?? true,
|
|
8020
|
+
groupFilter: options.controls?.groupFilter ?? true,
|
|
6570
8021
|
viewpointSelect: options.controls?.viewpointSelect ?? true,
|
|
6571
8022
|
inspector: options.controls?.inspector ?? true,
|
|
6572
8023
|
bookmarks: options.controls?.bookmarks ?? true
|
|
@@ -6576,6 +8027,7 @@ var WorldOrbit = (() => {
|
|
|
6576
8027
|
const toolbar = container.querySelector("[data-atlas-toolbar]");
|
|
6577
8028
|
const searchInput = container.querySelector("[data-atlas-search]");
|
|
6578
8029
|
const typeFilterSelect = container.querySelector("[data-atlas-type-filter]");
|
|
8030
|
+
const groupFilterSelect = container.querySelector("[data-atlas-group-filter]");
|
|
6579
8031
|
const viewpointSelect = container.querySelector("[data-atlas-viewpoint]");
|
|
6580
8032
|
const bookmarkButton = container.querySelector("[data-atlas-bookmark]");
|
|
6581
8033
|
const bookmarkList = container.querySelector("[data-atlas-bookmarks]");
|
|
@@ -6588,6 +8040,7 @@ var WorldOrbit = (() => {
|
|
|
6588
8040
|
const baseFilter = normalizeViewerFilter(options.initialFilter ?? null);
|
|
6589
8041
|
let searchQuery = options.initialQuery?.trim() ?? baseFilter?.query ?? "";
|
|
6590
8042
|
let objectTypeFilter = options.initialObjectType ?? (baseFilter?.objectTypes?.length === 1 ? baseFilter.objectTypes[0] : null);
|
|
8043
|
+
let groupFilter = baseFilter?.groupIds?.[0] ?? null;
|
|
6591
8044
|
let bookmarks = [];
|
|
6592
8045
|
let viewer;
|
|
6593
8046
|
viewer = createInteractiveViewer(stage, {
|
|
@@ -6635,6 +8088,7 @@ var WorldOrbit = (() => {
|
|
|
6635
8088
|
});
|
|
6636
8089
|
applyCurrentFilter();
|
|
6637
8090
|
populateViewpoints();
|
|
8091
|
+
populateGroups();
|
|
6638
8092
|
syncControlsFromFilter(viewer.getFilter());
|
|
6639
8093
|
renderBookmarks();
|
|
6640
8094
|
updateSearchResults();
|
|
@@ -6647,6 +8101,10 @@ var WorldOrbit = (() => {
|
|
|
6647
8101
|
objectTypeFilter = typeFilterSelect.value || null;
|
|
6648
8102
|
applyCurrentFilter();
|
|
6649
8103
|
});
|
|
8104
|
+
groupFilterSelect?.addEventListener("change", () => {
|
|
8105
|
+
groupFilter = groupFilterSelect.value || null;
|
|
8106
|
+
applyCurrentFilter();
|
|
8107
|
+
});
|
|
6650
8108
|
viewpointSelect?.addEventListener("change", () => {
|
|
6651
8109
|
const activeViewer = requireViewer();
|
|
6652
8110
|
if (!viewpointSelect.value) {
|
|
@@ -6788,6 +8246,7 @@ var WorldOrbit = (() => {
|
|
|
6788
8246
|
return api;
|
|
6789
8247
|
function refreshAfterInputChange() {
|
|
6790
8248
|
populateViewpoints();
|
|
8249
|
+
populateGroups();
|
|
6791
8250
|
applyCurrentFilter();
|
|
6792
8251
|
renderBookmarks();
|
|
6793
8252
|
updateSearchResults();
|
|
@@ -6804,19 +8263,23 @@ var WorldOrbit = (() => {
|
|
|
6804
8263
|
query: searchQuery || void 0,
|
|
6805
8264
|
objectTypes: objectTypeFilter ? [objectTypeFilter] : void 0,
|
|
6806
8265
|
tags: baseFilter?.tags,
|
|
6807
|
-
groupIds: baseFilter?.groupIds,
|
|
8266
|
+
groupIds: groupFilter ? [groupFilter] : baseFilter?.groupIds,
|
|
6808
8267
|
includeAncestors: baseFilter?.includeAncestors ?? true
|
|
6809
8268
|
});
|
|
6810
8269
|
}
|
|
6811
8270
|
function syncControlsFromFilter(filter) {
|
|
6812
8271
|
searchQuery = filter?.query?.trim() ?? "";
|
|
6813
8272
|
objectTypeFilter = filter?.objectTypes?.length === 1 ? filter.objectTypes[0] : null;
|
|
8273
|
+
groupFilter = filter?.groupIds?.length === 1 ? filter.groupIds[0] : null;
|
|
6814
8274
|
if (searchInput && document.activeElement !== searchInput) {
|
|
6815
8275
|
searchInput.value = searchQuery;
|
|
6816
8276
|
}
|
|
6817
8277
|
if (typeFilterSelect) {
|
|
6818
8278
|
typeFilterSelect.value = objectTypeFilter ?? "";
|
|
6819
8279
|
}
|
|
8280
|
+
if (groupFilterSelect) {
|
|
8281
|
+
groupFilterSelect.value = groupFilter ?? "";
|
|
8282
|
+
}
|
|
6820
8283
|
}
|
|
6821
8284
|
function populateViewpoints() {
|
|
6822
8285
|
if (!viewpointSelect) {
|
|
@@ -6830,6 +8293,17 @@ var WorldOrbit = (() => {
|
|
|
6830
8293
|
].join("");
|
|
6831
8294
|
viewpointSelect.value = active;
|
|
6832
8295
|
}
|
|
8296
|
+
function populateGroups() {
|
|
8297
|
+
if (!groupFilterSelect) {
|
|
8298
|
+
return;
|
|
8299
|
+
}
|
|
8300
|
+
const activeViewer = requireViewer();
|
|
8301
|
+
groupFilterSelect.innerHTML = [
|
|
8302
|
+
`<option value="">All groups</option>`,
|
|
8303
|
+
...activeViewer.getScene().semanticGroups.map((group) => `<option value="${escapeHtml2(group.id)}">${escapeHtml2(group.label)}</option>`)
|
|
8304
|
+
].join("");
|
|
8305
|
+
groupFilterSelect.value = groupFilter ?? "";
|
|
8306
|
+
}
|
|
6833
8307
|
function syncViewpointControl() {
|
|
6834
8308
|
if (!viewpointSelect) {
|
|
6835
8309
|
return;
|
|
@@ -6863,6 +8337,8 @@ var WorldOrbit = (() => {
|
|
|
6863
8337
|
projection: activeViewer.getScene().projection,
|
|
6864
8338
|
renderPreset: activeViewer.getScene().renderPreset,
|
|
6865
8339
|
groupCount: activeViewer.getScene().groups.length,
|
|
8340
|
+
semanticGroupCount: activeViewer.getScene().semanticGroups.length,
|
|
8341
|
+
relationCount: activeViewer.getScene().relations.length,
|
|
6866
8342
|
viewpointCount: activeViewer.getScene().viewpoints.length
|
|
6867
8343
|
}
|
|
6868
8344
|
};
|
|
@@ -6895,6 +8371,12 @@ var WorldOrbit = (() => {
|
|
|
6895
8371
|
<option value="phenomenon">Phenomenon</option>
|
|
6896
8372
|
</select>
|
|
6897
8373
|
</label>` : "",
|
|
8374
|
+
controls.groupFilter ? `<label class="wo-atlas-field">
|
|
8375
|
+
<span>Group</span>
|
|
8376
|
+
<select data-atlas-group-filter>
|
|
8377
|
+
<option value="">All groups</option>
|
|
8378
|
+
</select>
|
|
8379
|
+
</label>` : "",
|
|
6898
8380
|
controls.viewpointSelect ? `<label class="wo-atlas-field">
|
|
6899
8381
|
<span>Viewpoint</span>
|
|
6900
8382
|
<select data-atlas-viewpoint>
|