worldorbit 2.6.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -9
- package/dist/browser/core/dist/atlas-edit.d.ts +11 -0
- package/dist/browser/core/dist/atlas-edit.js +347 -0
- package/dist/browser/core/dist/atlas-utils.d.ts +22 -0
- package/dist/browser/core/dist/atlas-utils.js +189 -0
- package/dist/browser/core/dist/atlas-validate.d.ts +2 -0
- package/dist/browser/core/dist/atlas-validate.js +488 -0
- package/dist/browser/core/dist/diagnostics.d.ts +10 -0
- package/dist/browser/core/dist/diagnostics.js +109 -0
- package/dist/browser/core/dist/draft-parse.d.ts +3 -0
- package/dist/browser/core/dist/draft-parse.js +1654 -0
- package/dist/browser/core/dist/draft.d.ts +21 -0
- package/dist/browser/core/dist/draft.js +482 -0
- package/dist/browser/core/dist/errors.d.ts +7 -0
- package/dist/browser/core/dist/errors.js +16 -0
- package/dist/browser/core/dist/format.d.ts +4 -0
- package/dist/browser/core/dist/format.js +613 -0
- package/dist/browser/core/dist/index.d.ts +29 -0
- package/dist/browser/core/dist/index.js +35 -6542
- package/dist/browser/core/dist/load.d.ts +4 -0
- package/dist/browser/core/dist/load.js +182 -0
- package/dist/browser/core/dist/markdown.d.ts +2 -0
- package/dist/browser/core/dist/markdown.js +37 -0
- package/dist/browser/core/dist/normalize.d.ts +2 -0
- package/dist/browser/core/dist/normalize.js +312 -0
- package/dist/browser/core/dist/parse.d.ts +2 -0
- package/dist/browser/core/dist/parse.js +133 -0
- package/dist/browser/core/dist/scene.d.ts +3 -0
- package/dist/browser/core/dist/scene.js +1901 -0
- package/dist/browser/core/dist/schema.d.ts +8 -0
- package/dist/browser/core/dist/schema.js +298 -0
- package/dist/browser/core/dist/spatial-scene.d.ts +3 -0
- package/dist/browser/core/dist/spatial-scene.js +420 -0
- package/dist/browser/core/dist/tokenize.d.ts +4 -0
- package/dist/browser/core/dist/tokenize.js +68 -0
- package/dist/browser/core/dist/types.d.ts +637 -0
- package/dist/browser/core/dist/types.js +1 -0
- package/dist/browser/core/dist/validate.d.ts +2 -0
- package/dist/browser/core/dist/validate.js +56 -0
- package/dist/browser/editor/dist/editor.d.ts +2 -0
- package/dist/browser/editor/dist/editor.js +3700 -0
- package/dist/browser/editor/dist/index.d.ts +2 -0
- package/dist/browser/editor/dist/index.js +1 -12250
- package/dist/browser/editor/dist/types.d.ts +59 -0
- package/dist/browser/editor/dist/types.js +1 -0
- package/dist/browser/markdown/dist/html.d.ts +3 -0
- package/dist/browser/markdown/dist/html.js +64 -0
- package/dist/browser/markdown/dist/index.d.ts +4 -0
- package/dist/browser/markdown/dist/index.js +3 -6179
- package/dist/browser/markdown/dist/rehype.d.ts +10 -0
- package/dist/browser/markdown/dist/rehype.js +49 -0
- package/dist/browser/markdown/dist/remark.d.ts +9 -0
- package/dist/browser/markdown/dist/remark.js +28 -0
- package/dist/browser/markdown/dist/types.d.ts +11 -0
- package/dist/browser/markdown/dist/types.js +1 -0
- package/dist/browser/viewer/dist/atlas-state.d.ts +12 -0
- package/dist/browser/viewer/dist/atlas-state.js +269 -0
- package/dist/browser/viewer/dist/atlas-viewer.d.ts +2 -0
- package/dist/browser/viewer/dist/atlas-viewer.js +495 -0
- package/dist/browser/viewer/dist/custom-element.d.ts +1 -0
- package/dist/browser/viewer/dist/custom-element.js +78 -0
- package/dist/browser/viewer/dist/embed.d.ts +24 -0
- package/dist/browser/viewer/dist/embed.js +172 -0
- package/dist/browser/viewer/dist/errors.d.ts +6 -0
- package/dist/browser/viewer/dist/errors.js +12 -0
- package/dist/browser/viewer/dist/index.d.ts +10 -0
- package/dist/browser/viewer/dist/index.js +9 -8334
- package/dist/browser/viewer/dist/minimap.d.ts +3 -0
- package/dist/browser/viewer/dist/minimap.js +63 -0
- package/dist/browser/viewer/dist/render.d.ts +6 -0
- package/dist/browser/viewer/dist/render.js +670 -0
- package/dist/browser/viewer/dist/runtime-3d.d.ts +19 -0
- package/dist/browser/viewer/dist/runtime-3d.js +494 -0
- package/dist/browser/viewer/dist/theme.d.ts +4 -0
- package/dist/browser/viewer/dist/theme.js +103 -0
- package/dist/browser/viewer/dist/tooltip.d.ts +3 -0
- package/dist/browser/viewer/dist/tooltip.js +198 -0
- package/dist/browser/viewer/dist/types.d.ts +292 -0
- package/dist/browser/viewer/dist/types.js +1 -0
- package/dist/browser/viewer/dist/vendor/three.module.js +53032 -0
- package/dist/browser/viewer/dist/viewer-state.d.ts +19 -0
- package/dist/browser/viewer/dist/viewer-state.js +162 -0
- package/dist/browser/viewer/dist/viewer.d.ts +2 -0
- package/dist/browser/viewer/dist/viewer.js +1662 -0
- package/dist/unpkg/core/dist/atlas-edit.d.ts +11 -0
- package/dist/unpkg/core/dist/atlas-edit.js +347 -0
- package/dist/unpkg/core/dist/atlas-utils.d.ts +22 -0
- package/dist/unpkg/core/dist/atlas-utils.js +189 -0
- package/dist/unpkg/core/dist/atlas-validate.d.ts +2 -0
- package/dist/unpkg/core/dist/atlas-validate.js +488 -0
- package/dist/unpkg/core/dist/diagnostics.d.ts +10 -0
- package/dist/unpkg/core/dist/diagnostics.js +109 -0
- package/dist/unpkg/core/dist/draft-parse.d.ts +3 -0
- package/dist/unpkg/core/dist/draft-parse.js +1654 -0
- package/dist/unpkg/core/dist/draft.d.ts +21 -0
- package/dist/unpkg/core/dist/draft.js +482 -0
- package/dist/unpkg/core/dist/errors.d.ts +7 -0
- package/dist/unpkg/core/dist/errors.js +16 -0
- package/dist/unpkg/core/dist/format.d.ts +4 -0
- package/dist/unpkg/core/dist/format.js +613 -0
- package/dist/unpkg/core/dist/index.d.ts +29 -0
- package/dist/unpkg/core/dist/index.js +35 -6614
- package/dist/unpkg/core/dist/load.d.ts +4 -0
- package/dist/unpkg/core/dist/load.js +182 -0
- package/dist/unpkg/core/dist/markdown.d.ts +2 -0
- package/dist/unpkg/core/dist/markdown.js +37 -0
- package/dist/unpkg/core/dist/normalize.d.ts +2 -0
- package/dist/unpkg/core/dist/normalize.js +312 -0
- package/dist/unpkg/core/dist/parse.d.ts +2 -0
- package/dist/unpkg/core/dist/parse.js +133 -0
- package/dist/unpkg/core/dist/scene.d.ts +3 -0
- package/dist/unpkg/core/dist/scene.js +1901 -0
- package/dist/unpkg/core/dist/schema.d.ts +8 -0
- package/dist/unpkg/core/dist/schema.js +298 -0
- package/dist/unpkg/core/dist/spatial-scene.d.ts +3 -0
- package/dist/unpkg/core/dist/spatial-scene.js +420 -0
- package/dist/unpkg/core/dist/tokenize.d.ts +4 -0
- package/dist/unpkg/core/dist/tokenize.js +68 -0
- package/dist/unpkg/core/dist/types.d.ts +637 -0
- package/dist/unpkg/core/dist/types.js +1 -0
- package/dist/unpkg/core/dist/validate.d.ts +2 -0
- package/dist/unpkg/core/dist/validate.js +56 -0
- package/dist/unpkg/editor/dist/editor.d.ts +2 -0
- package/dist/unpkg/editor/dist/editor.js +3700 -0
- package/dist/unpkg/editor/dist/index.d.ts +2 -0
- package/dist/unpkg/editor/dist/index.js +1 -12275
- package/dist/unpkg/editor/dist/types.d.ts +59 -0
- package/dist/unpkg/editor/dist/types.js +1 -0
- package/dist/unpkg/markdown/dist/html.d.ts +3 -0
- package/dist/unpkg/markdown/dist/html.js +64 -0
- package/dist/unpkg/markdown/dist/index.d.ts +4 -0
- package/dist/unpkg/markdown/dist/index.js +3 -6207
- package/dist/unpkg/markdown/dist/rehype.d.ts +10 -0
- package/dist/unpkg/markdown/dist/rehype.js +49 -0
- package/dist/unpkg/markdown/dist/remark.d.ts +9 -0
- package/dist/unpkg/markdown/dist/remark.js +28 -0
- package/dist/unpkg/markdown/dist/types.d.ts +11 -0
- package/dist/unpkg/markdown/dist/types.js +1 -0
- package/dist/unpkg/viewer/dist/atlas-state.d.ts +12 -0
- package/dist/unpkg/viewer/dist/atlas-state.js +269 -0
- package/dist/unpkg/viewer/dist/atlas-viewer.d.ts +2 -0
- package/dist/unpkg/viewer/dist/atlas-viewer.js +495 -0
- package/dist/unpkg/viewer/dist/custom-element.d.ts +1 -0
- package/dist/unpkg/viewer/dist/custom-element.js +78 -0
- package/dist/unpkg/viewer/dist/embed.d.ts +24 -0
- package/dist/unpkg/viewer/dist/embed.js +172 -0
- package/dist/unpkg/viewer/dist/errors.d.ts +6 -0
- package/dist/unpkg/viewer/dist/errors.js +12 -0
- package/dist/unpkg/viewer/dist/index.d.ts +10 -0
- package/dist/unpkg/viewer/dist/index.js +9 -8391
- package/dist/unpkg/viewer/dist/minimap.d.ts +3 -0
- package/dist/unpkg/viewer/dist/minimap.js +63 -0
- package/dist/unpkg/viewer/dist/render.d.ts +6 -0
- package/dist/unpkg/viewer/dist/render.js +670 -0
- package/dist/unpkg/viewer/dist/runtime-3d.d.ts +19 -0
- package/dist/unpkg/viewer/dist/runtime-3d.js +494 -0
- package/dist/unpkg/viewer/dist/theme.d.ts +4 -0
- package/dist/unpkg/viewer/dist/theme.js +103 -0
- package/dist/unpkg/viewer/dist/tooltip.d.ts +3 -0
- package/dist/unpkg/viewer/dist/tooltip.js +198 -0
- package/dist/unpkg/viewer/dist/types.d.ts +292 -0
- package/dist/unpkg/viewer/dist/types.js +1 -0
- package/dist/unpkg/viewer/dist/vendor/three.module.js +53032 -0
- package/dist/unpkg/viewer/dist/viewer-state.d.ts +19 -0
- package/dist/unpkg/viewer/dist/viewer-state.js +162 -0
- package/dist/unpkg/viewer/dist/viewer.d.ts +2 -0
- package/dist/unpkg/viewer/dist/viewer.js +1662 -0
- package/dist/unpkg/worldorbit-core.min.js +10 -10
- package/dist/unpkg/worldorbit-editor.min.js +4109 -256
- package/dist/unpkg/worldorbit-markdown.min.js +26 -26
- package/dist/unpkg/worldorbit-viewer.min.js +3945 -92
- package/dist/unpkg/worldorbit.js +32219 -199
- package/dist/unpkg/worldorbit.min.js +3949 -96
- package/package.json +1 -1
- package/packages/core/dist/index.d.ts +1 -0
- package/packages/core/dist/index.js +1 -0
- package/packages/core/dist/spatial-scene.d.ts +3 -0
- package/packages/core/dist/spatial-scene.js +420 -0
- package/packages/core/dist/types.d.ts +105 -0
- package/packages/editor/dist/editor.js +25 -4
- package/packages/editor/dist/types.d.ts +4 -0
- package/packages/markdown/dist/html.js +10 -3
- package/packages/viewer/dist/atlas-state.js +3 -0
- package/packages/viewer/dist/atlas-viewer.js +1 -0
- package/packages/viewer/dist/custom-element.js +18 -4
- package/packages/viewer/dist/embed.d.ts +5 -1
- package/packages/viewer/dist/embed.js +58 -24
- package/packages/viewer/dist/errors.d.ts +6 -0
- package/packages/viewer/dist/errors.js +12 -0
- package/packages/viewer/dist/index.d.ts +1 -0
- package/packages/viewer/dist/index.js +1 -0
- package/packages/viewer/dist/runtime-3d.d.ts +19 -0
- package/packages/viewer/dist/runtime-3d.js +494 -0
- package/packages/viewer/dist/types.d.ts +21 -2
- package/packages/viewer/dist/vendor/three.module.js +53032 -0
- package/packages/viewer/dist/viewer.js +501 -41
package/README.md
CHANGED
|
@@ -118,7 +118,6 @@ For direct browser usage, use the browser bundle:
|
|
|
118
118
|
<html>
|
|
119
119
|
<head>
|
|
120
120
|
<meta charset="utf-8" />
|
|
121
|
-
<script src="https://unpkg.com/worldorbit@2.6.0/dist/unpkg/worldorbit.min.js"></script>
|
|
122
121
|
<style>
|
|
123
122
|
html, body {
|
|
124
123
|
margin: 0;
|
|
@@ -135,7 +134,12 @@ For direct browser usage, use the browser bundle:
|
|
|
135
134
|
<body>
|
|
136
135
|
<div id="view"></div>
|
|
137
136
|
|
|
138
|
-
<script>
|
|
137
|
+
<script type="module">
|
|
138
|
+
import {
|
|
139
|
+
createInteractiveViewer,
|
|
140
|
+
loadWorldOrbitSource
|
|
141
|
+
} from "https://unpkg.com/worldorbit@3.0.0/dist/unpkg/worldorbit.esm.js";
|
|
142
|
+
|
|
139
143
|
const source = `
|
|
140
144
|
schema 2.5
|
|
141
145
|
|
|
@@ -148,9 +152,9 @@ object planet Naar
|
|
|
148
152
|
semiMajor 1.18au
|
|
149
153
|
`.trim();
|
|
150
154
|
|
|
151
|
-
const loaded =
|
|
155
|
+
const loaded = loadWorldOrbitSource(source);
|
|
152
156
|
|
|
153
|
-
|
|
157
|
+
createInteractiveViewer(document.getElementById("view"), {
|
|
154
158
|
document: loaded.document
|
|
155
159
|
});
|
|
156
160
|
</script>
|
|
@@ -158,7 +162,7 @@ object planet Naar
|
|
|
158
162
|
</html>
|
|
159
163
|
```
|
|
160
164
|
|
|
161
|
-
For browser usage,
|
|
165
|
+
For browser usage today, prefer the ESM entry point `worldorbit.esm.js`.
|
|
162
166
|
|
|
163
167
|
## Static and Interactive Rendering
|
|
164
168
|
|
|
@@ -351,6 +355,7 @@ createInteractiveViewer(document.getElementById("preview"), {
|
|
|
351
355
|
document: loaded.document,
|
|
352
356
|
projection: "isometric",
|
|
353
357
|
theme: "atlas",
|
|
358
|
+
viewMode: "3d",
|
|
354
359
|
});
|
|
355
360
|
```
|
|
356
361
|
|
|
@@ -427,9 +432,12 @@ const scene = renderDocumentToScene(loaded.document, {
|
|
|
427
432
|
|
|
428
433
|
## Viewer Capabilities
|
|
429
434
|
|
|
430
|
-
Viewer features in `
|
|
435
|
+
Viewer features in `v3.0.0` include:
|
|
431
436
|
|
|
432
437
|
* scene-based SVG rendering
|
|
438
|
+
* renderer-neutral spatial scenes through `renderDocumentToSpatialScene(...)`
|
|
439
|
+
* a full 3D viewer mode on the same documents and placements as 2D
|
|
440
|
+
* deterministic orbit animation with play, pause, reset, and speed controls
|
|
433
441
|
* projections: `topdown`, `isometric`, `orthographic`, and `perspective`
|
|
434
442
|
* theme presets: `atlas`, `nightglass`, `ember`
|
|
435
443
|
* layer controls for background, guides, orbits, events, objects, labels, metadata, and relations
|
|
@@ -442,7 +450,7 @@ Viewer features in `v2.6` include:
|
|
|
442
450
|
|
|
443
451
|
## Markdown Integration
|
|
444
452
|
|
|
445
|
-
Use `worldorbit/markdown` to transform fenced `worldorbit` blocks into static or interactive output.
|
|
453
|
+
Use `worldorbit/markdown` to transform fenced `worldorbit` blocks into static output, interactive 2D output, or interactive 3D output.
|
|
446
454
|
|
|
447
455
|
```ts
|
|
448
456
|
import rehypeStringify from "rehype-stringify";
|
|
@@ -455,7 +463,7 @@ import { remarkWorldOrbit } from "worldorbit/markdown";
|
|
|
455
463
|
const html = String(
|
|
456
464
|
await unified()
|
|
457
465
|
.use(remarkParse)
|
|
458
|
-
.use(remarkWorldOrbit, { mode: "interactive" })
|
|
466
|
+
.use(remarkWorldOrbit, { mode: "interactive-3d" })
|
|
459
467
|
.use(remarkRehype, { allowDangerousHtml: true })
|
|
460
468
|
.use(rehypeStringify, { allowDangerousHtml: true })
|
|
461
469
|
.process(markdownSource),
|
|
@@ -468,7 +476,7 @@ In the browser:
|
|
|
468
476
|
import { mountWorldOrbitEmbeds } from "worldorbit/viewer";
|
|
469
477
|
|
|
470
478
|
mountWorldOrbitEmbeds(document, {
|
|
471
|
-
mode: "interactive",
|
|
479
|
+
mode: "interactive-3d",
|
|
472
480
|
});
|
|
473
481
|
```
|
|
474
482
|
|
|
@@ -477,6 +485,8 @@ mountWorldOrbitEmbeds(document, {
|
|
|
477
485
|
Examples live in:
|
|
478
486
|
|
|
479
487
|
* [examples/minimal.worldorbit](./examples/minimal.worldorbit)
|
|
488
|
+
* [examples/minimal-3d.worldorbit](./examples/minimal-3d.worldorbit)
|
|
489
|
+
* [examples/showcase-3d.worldorbit](./examples/showcase-3d.worldorbit)
|
|
480
490
|
* [examples/schema25-camera.worldorbit](./examples/schema25-camera.worldorbit)
|
|
481
491
|
* [examples/schema25-event-snapshot.worldorbit](./examples/schema25-event-snapshot.worldorbit)
|
|
482
492
|
* [examples/studio.schema25.worldorbit](./examples/studio.schema25.worldorbit)
|
|
@@ -496,6 +506,7 @@ Browser-facing examples and demos live in the repository under `demo/`, `studio/
|
|
|
496
506
|
* [migration guide: v1 to v2](./docs/migration-v1-to-v2.md)
|
|
497
507
|
* [migration guide: v2.0 to v2.1](./docs/migration-v2-to-v2.1.md)
|
|
498
508
|
* [migration guide: v2.1 to v2.5](./docs/migration-v2.1-to-v2.5.md)
|
|
509
|
+
* [migration guide: v2.6 to v3.0](./docs/migration-v2.6-to-v3.0.md)
|
|
499
510
|
* [language reference](./docs/language-reference.md)
|
|
500
511
|
* [language reference (DE)](./docs/language-reference.de.md)
|
|
501
512
|
* [API inventory](./docs/api-inventory.md)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AtlasDocumentPath, AtlasResolvedDiagnostic, WorldOrbitAtlasDocument, WorldOrbitAtlasDocumentVersion, WorldOrbitDiagnostic } from "./types.js";
|
|
2
|
+
export declare function createEmptyAtlasDocument(systemId?: string, version?: WorldOrbitAtlasDocumentVersion): WorldOrbitAtlasDocument;
|
|
3
|
+
export declare function cloneAtlasDocument(document: WorldOrbitAtlasDocument): WorldOrbitAtlasDocument;
|
|
4
|
+
export declare function listAtlasDocumentPaths(document: WorldOrbitAtlasDocument): AtlasDocumentPath[];
|
|
5
|
+
export declare function getAtlasDocumentNode(document: WorldOrbitAtlasDocument, path: AtlasDocumentPath): unknown;
|
|
6
|
+
export declare function upsertAtlasDocumentNode(document: WorldOrbitAtlasDocument, path: AtlasDocumentPath, value: unknown): WorldOrbitAtlasDocument;
|
|
7
|
+
export declare function updateAtlasDocumentNode(document: WorldOrbitAtlasDocument, path: AtlasDocumentPath, updater: (value: unknown) => unknown): WorldOrbitAtlasDocument;
|
|
8
|
+
export declare function removeAtlasDocumentNode(document: WorldOrbitAtlasDocument, path: AtlasDocumentPath): WorldOrbitAtlasDocument;
|
|
9
|
+
export declare function resolveAtlasDiagnostics(document: WorldOrbitAtlasDocument, diagnostics: WorldOrbitDiagnostic[]): AtlasResolvedDiagnostic[];
|
|
10
|
+
export declare function resolveAtlasDiagnosticPath(document: WorldOrbitAtlasDocument, diagnostic: WorldOrbitDiagnostic): AtlasDocumentPath | null;
|
|
11
|
+
export declare function validateAtlasDocumentWithDiagnostics(document: WorldOrbitAtlasDocument): AtlasResolvedDiagnostic[];
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import { collectAtlasDiagnostics } from "./atlas-validate.js";
|
|
2
|
+
export function createEmptyAtlasDocument(systemId = "WorldOrbit", version = "2.5") {
|
|
3
|
+
return {
|
|
4
|
+
format: "worldorbit",
|
|
5
|
+
version,
|
|
6
|
+
schemaVersion: version,
|
|
7
|
+
sourceVersion: "1.0",
|
|
8
|
+
system: {
|
|
9
|
+
type: "system",
|
|
10
|
+
id: systemId,
|
|
11
|
+
title: systemId,
|
|
12
|
+
description: null,
|
|
13
|
+
epoch: null,
|
|
14
|
+
referencePlane: null,
|
|
15
|
+
defaults: {
|
|
16
|
+
view: "topdown",
|
|
17
|
+
scale: null,
|
|
18
|
+
units: null,
|
|
19
|
+
preset: null,
|
|
20
|
+
theme: null,
|
|
21
|
+
},
|
|
22
|
+
atlasMetadata: {},
|
|
23
|
+
viewpoints: [],
|
|
24
|
+
annotations: [],
|
|
25
|
+
},
|
|
26
|
+
groups: [],
|
|
27
|
+
relations: [],
|
|
28
|
+
events: [],
|
|
29
|
+
objects: [],
|
|
30
|
+
diagnostics: [],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function cloneAtlasDocument(document) {
|
|
34
|
+
return structuredClone(document);
|
|
35
|
+
}
|
|
36
|
+
export function listAtlasDocumentPaths(document) {
|
|
37
|
+
const paths = [{ kind: "system" }, { kind: "defaults" }];
|
|
38
|
+
if (document.system) {
|
|
39
|
+
for (const key of Object.keys(document.system.atlasMetadata).sort()) {
|
|
40
|
+
paths.push({ kind: "metadata", key });
|
|
41
|
+
}
|
|
42
|
+
for (const viewpoint of [...document.system.viewpoints].sort(compareIdLike)) {
|
|
43
|
+
paths.push({ kind: "viewpoint", id: viewpoint.id });
|
|
44
|
+
}
|
|
45
|
+
for (const annotation of [...document.system.annotations].sort(compareIdLike)) {
|
|
46
|
+
paths.push({ kind: "annotation", id: annotation.id });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
for (const group of [...document.groups].sort(compareIdLike)) {
|
|
50
|
+
paths.push({ kind: "group", id: group.id });
|
|
51
|
+
}
|
|
52
|
+
for (const relation of [...document.relations].sort(compareIdLike)) {
|
|
53
|
+
paths.push({ kind: "relation", id: relation.id });
|
|
54
|
+
}
|
|
55
|
+
for (const event of [...document.events].sort(compareIdLike)) {
|
|
56
|
+
paths.push({ kind: "event", id: event.id });
|
|
57
|
+
for (const pose of [...event.positions].sort(comparePoseObjectId)) {
|
|
58
|
+
paths.push({ kind: "event-pose", id: event.id, key: pose.objectId });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
for (const object of [...document.objects].sort(compareIdLike)) {
|
|
62
|
+
paths.push({ kind: "object", id: object.id });
|
|
63
|
+
}
|
|
64
|
+
return paths;
|
|
65
|
+
}
|
|
66
|
+
export function getAtlasDocumentNode(document, path) {
|
|
67
|
+
switch (path.kind) {
|
|
68
|
+
case "system":
|
|
69
|
+
return document.system;
|
|
70
|
+
case "defaults":
|
|
71
|
+
return document.system?.defaults ?? null;
|
|
72
|
+
case "metadata":
|
|
73
|
+
return path.key ? (document.system?.atlasMetadata[path.key] ?? null) : null;
|
|
74
|
+
case "group":
|
|
75
|
+
return path.id ? findGroup(document, path.id) : null;
|
|
76
|
+
case "event":
|
|
77
|
+
return path.id ? findEvent(document, path.id) : null;
|
|
78
|
+
case "event-pose":
|
|
79
|
+
return path.id && path.key ? findEventPose(document, path.id, path.key) : null;
|
|
80
|
+
case "object":
|
|
81
|
+
return path.id ? findObject(document, path.id) : null;
|
|
82
|
+
case "viewpoint":
|
|
83
|
+
return path.id ? findViewpoint(document.system, path.id) : null;
|
|
84
|
+
case "annotation":
|
|
85
|
+
return path.id ? findAnnotation(document.system, path.id) : null;
|
|
86
|
+
case "relation":
|
|
87
|
+
return path.id ? findRelation(document, path.id) : null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
export function upsertAtlasDocumentNode(document, path, value) {
|
|
91
|
+
const next = cloneAtlasDocument(document);
|
|
92
|
+
const system = ensureSystem(next);
|
|
93
|
+
switch (path.kind) {
|
|
94
|
+
case "system":
|
|
95
|
+
next.system = value;
|
|
96
|
+
return next;
|
|
97
|
+
case "defaults":
|
|
98
|
+
system.defaults = {
|
|
99
|
+
...system.defaults,
|
|
100
|
+
...value,
|
|
101
|
+
};
|
|
102
|
+
return next;
|
|
103
|
+
case "metadata":
|
|
104
|
+
if (!path.key) {
|
|
105
|
+
throw new Error('Metadata updates require a "key" value.');
|
|
106
|
+
}
|
|
107
|
+
if (value === null || value === undefined || value === "") {
|
|
108
|
+
delete system.atlasMetadata[path.key];
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
system.atlasMetadata[path.key] = String(value);
|
|
112
|
+
}
|
|
113
|
+
return next;
|
|
114
|
+
case "group":
|
|
115
|
+
if (!path.id) {
|
|
116
|
+
throw new Error('Group updates require an "id" value.');
|
|
117
|
+
}
|
|
118
|
+
upsertById(next.groups, value);
|
|
119
|
+
return next;
|
|
120
|
+
case "event":
|
|
121
|
+
if (!path.id) {
|
|
122
|
+
throw new Error('Event updates require an "id" value.');
|
|
123
|
+
}
|
|
124
|
+
upsertById(next.events, value);
|
|
125
|
+
return next;
|
|
126
|
+
case "event-pose":
|
|
127
|
+
if (!path.id || !path.key) {
|
|
128
|
+
throw new Error('Event pose updates require an event "id" and pose "key" value.');
|
|
129
|
+
}
|
|
130
|
+
upsertEventPose(next.events, path.id, value);
|
|
131
|
+
return next;
|
|
132
|
+
case "object":
|
|
133
|
+
if (!path.id) {
|
|
134
|
+
throw new Error('Object updates require an "id" value.');
|
|
135
|
+
}
|
|
136
|
+
upsertById(next.objects, value);
|
|
137
|
+
return next;
|
|
138
|
+
case "viewpoint":
|
|
139
|
+
if (!path.id) {
|
|
140
|
+
throw new Error('Viewpoint updates require an "id" value.');
|
|
141
|
+
}
|
|
142
|
+
upsertById(system.viewpoints, value);
|
|
143
|
+
return next;
|
|
144
|
+
case "annotation":
|
|
145
|
+
if (!path.id) {
|
|
146
|
+
throw new Error('Annotation updates require an "id" value.');
|
|
147
|
+
}
|
|
148
|
+
upsertById(system.annotations, value);
|
|
149
|
+
return next;
|
|
150
|
+
case "relation":
|
|
151
|
+
if (!path.id) {
|
|
152
|
+
throw new Error('Relation updates require an "id" value.');
|
|
153
|
+
}
|
|
154
|
+
upsertById(next.relations, value);
|
|
155
|
+
return next;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
export function updateAtlasDocumentNode(document, path, updater) {
|
|
159
|
+
return upsertAtlasDocumentNode(document, path, updater(getAtlasDocumentNode(document, path)));
|
|
160
|
+
}
|
|
161
|
+
export function removeAtlasDocumentNode(document, path) {
|
|
162
|
+
const next = cloneAtlasDocument(document);
|
|
163
|
+
const system = ensureSystem(next);
|
|
164
|
+
switch (path.kind) {
|
|
165
|
+
case "metadata":
|
|
166
|
+
if (path.key) {
|
|
167
|
+
delete system.atlasMetadata[path.key];
|
|
168
|
+
}
|
|
169
|
+
return next;
|
|
170
|
+
case "object":
|
|
171
|
+
if (path.id) {
|
|
172
|
+
next.objects = next.objects.filter((object) => object.id !== path.id);
|
|
173
|
+
}
|
|
174
|
+
return next;
|
|
175
|
+
case "group":
|
|
176
|
+
if (path.id) {
|
|
177
|
+
next.groups = next.groups.filter((group) => group.id !== path.id);
|
|
178
|
+
}
|
|
179
|
+
return next;
|
|
180
|
+
case "event":
|
|
181
|
+
if (path.id) {
|
|
182
|
+
next.events = next.events.filter((event) => event.id !== path.id);
|
|
183
|
+
}
|
|
184
|
+
return next;
|
|
185
|
+
case "event-pose":
|
|
186
|
+
if (path.id && path.key) {
|
|
187
|
+
const event = findEvent(next, path.id);
|
|
188
|
+
if (event) {
|
|
189
|
+
event.positions = event.positions.filter((pose) => pose.objectId !== path.key);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return next;
|
|
193
|
+
case "viewpoint":
|
|
194
|
+
if (path.id) {
|
|
195
|
+
system.viewpoints = system.viewpoints.filter((viewpoint) => viewpoint.id !== path.id);
|
|
196
|
+
}
|
|
197
|
+
return next;
|
|
198
|
+
case "annotation":
|
|
199
|
+
if (path.id) {
|
|
200
|
+
system.annotations = system.annotations.filter((annotation) => annotation.id !== path.id);
|
|
201
|
+
}
|
|
202
|
+
return next;
|
|
203
|
+
case "relation":
|
|
204
|
+
if (path.id) {
|
|
205
|
+
next.relations = next.relations.filter((relation) => relation.id !== path.id);
|
|
206
|
+
}
|
|
207
|
+
return next;
|
|
208
|
+
default:
|
|
209
|
+
return next;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
export function resolveAtlasDiagnostics(document, diagnostics) {
|
|
213
|
+
return diagnostics.map((diagnostic) => ({
|
|
214
|
+
diagnostic,
|
|
215
|
+
path: resolveAtlasDiagnosticPath(document, diagnostic),
|
|
216
|
+
}));
|
|
217
|
+
}
|
|
218
|
+
export function resolveAtlasDiagnosticPath(document, diagnostic) {
|
|
219
|
+
if (diagnostic.objectId && findObject(document, diagnostic.objectId)) {
|
|
220
|
+
return {
|
|
221
|
+
kind: "object",
|
|
222
|
+
id: diagnostic.objectId,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
if (diagnostic.field?.startsWith("group.")) {
|
|
226
|
+
const parts = diagnostic.field.split(".");
|
|
227
|
+
if (parts[1] && findGroup(document, parts[1])) {
|
|
228
|
+
return {
|
|
229
|
+
kind: "group",
|
|
230
|
+
id: parts[1],
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (diagnostic.field?.startsWith("viewpoint.")) {
|
|
235
|
+
const parts = diagnostic.field.split(".");
|
|
236
|
+
if (parts[1] && findViewpoint(document.system, parts[1])) {
|
|
237
|
+
return {
|
|
238
|
+
kind: "viewpoint",
|
|
239
|
+
id: parts[1],
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (diagnostic.field?.startsWith("annotation.")) {
|
|
244
|
+
const parts = diagnostic.field.split(".");
|
|
245
|
+
if (parts[1] && findAnnotation(document.system, parts[1])) {
|
|
246
|
+
return {
|
|
247
|
+
kind: "annotation",
|
|
248
|
+
id: parts[1],
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (diagnostic.field?.startsWith("relation.")) {
|
|
253
|
+
const parts = diagnostic.field.split(".");
|
|
254
|
+
if (parts[1] && findRelation(document, parts[1])) {
|
|
255
|
+
return {
|
|
256
|
+
kind: "relation",
|
|
257
|
+
id: parts[1],
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (diagnostic.field?.startsWith("event.")) {
|
|
262
|
+
const parts = diagnostic.field.split(".");
|
|
263
|
+
if (parts[1] && findEvent(document, parts[1])) {
|
|
264
|
+
if (parts[2] === "pose" && parts[3] && findEventPose(document, parts[1], parts[3])) {
|
|
265
|
+
return {
|
|
266
|
+
kind: "event-pose",
|
|
267
|
+
id: parts[1],
|
|
268
|
+
key: parts[3],
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
kind: "event",
|
|
273
|
+
id: parts[1],
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (diagnostic.field && diagnostic.field in ensureSystem(document).atlasMetadata) {
|
|
278
|
+
return {
|
|
279
|
+
kind: "metadata",
|
|
280
|
+
key: diagnostic.field,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
export function validateAtlasDocumentWithDiagnostics(document) {
|
|
286
|
+
const diagnostics = [
|
|
287
|
+
...document.diagnostics,
|
|
288
|
+
...collectAtlasDiagnostics(document, document.version),
|
|
289
|
+
];
|
|
290
|
+
return resolveAtlasDiagnostics(document, diagnostics);
|
|
291
|
+
}
|
|
292
|
+
function ensureSystem(document) {
|
|
293
|
+
if (document.system) {
|
|
294
|
+
return document.system;
|
|
295
|
+
}
|
|
296
|
+
document.system = createEmptyAtlasDocument().system;
|
|
297
|
+
return document.system;
|
|
298
|
+
}
|
|
299
|
+
function findObject(document, objectId) {
|
|
300
|
+
return document.objects.find((object) => object.id === objectId) ?? null;
|
|
301
|
+
}
|
|
302
|
+
function findGroup(document, groupId) {
|
|
303
|
+
return document.groups.find((group) => group.id === groupId) ?? null;
|
|
304
|
+
}
|
|
305
|
+
function findRelation(document, relationId) {
|
|
306
|
+
return document.relations.find((relation) => relation.id === relationId) ?? null;
|
|
307
|
+
}
|
|
308
|
+
function findEvent(document, eventId) {
|
|
309
|
+
return document.events.find((event) => event.id === eventId) ?? null;
|
|
310
|
+
}
|
|
311
|
+
function findEventPose(document, eventId, objectId) {
|
|
312
|
+
return findEvent(document, eventId)?.positions.find((pose) => pose.objectId === objectId) ?? null;
|
|
313
|
+
}
|
|
314
|
+
function findViewpoint(system, viewpointId) {
|
|
315
|
+
return system?.viewpoints.find((viewpoint) => viewpoint.id === viewpointId) ?? null;
|
|
316
|
+
}
|
|
317
|
+
function findAnnotation(system, annotationId) {
|
|
318
|
+
return system?.annotations.find((annotation) => annotation.id === annotationId) ?? null;
|
|
319
|
+
}
|
|
320
|
+
function upsertById(items, value) {
|
|
321
|
+
const index = items.findIndex((item) => item.id === value.id);
|
|
322
|
+
if (index === -1) {
|
|
323
|
+
items.push(value);
|
|
324
|
+
items.sort(compareIdLike);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
items[index] = value;
|
|
328
|
+
}
|
|
329
|
+
function upsertEventPose(events, eventId, value) {
|
|
330
|
+
const event = events.find((entry) => entry.id === eventId);
|
|
331
|
+
if (!event) {
|
|
332
|
+
throw new Error(`Unknown event "${eventId}" for pose update.`);
|
|
333
|
+
}
|
|
334
|
+
const index = event.positions.findIndex((entry) => entry.objectId === value.objectId);
|
|
335
|
+
if (index === -1) {
|
|
336
|
+
event.positions.push(value);
|
|
337
|
+
event.positions.sort(comparePoseObjectId);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
event.positions[index] = value;
|
|
341
|
+
}
|
|
342
|
+
function compareIdLike(left, right) {
|
|
343
|
+
return left.id.localeCompare(right.id);
|
|
344
|
+
}
|
|
345
|
+
function comparePoseObjectId(left, right) {
|
|
346
|
+
return left.objectId.localeCompare(right.objectId);
|
|
347
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { AstFieldNode, AstSourceLocation, AtReference, NormalizedValue, UnitValue, WorldOrbitObjectType } from "./types.js";
|
|
2
|
+
export interface AtlasFieldLike {
|
|
3
|
+
key: string;
|
|
4
|
+
values: string[];
|
|
5
|
+
location: AstSourceLocation;
|
|
6
|
+
}
|
|
7
|
+
export declare function normalizeIdentifier(value: string): string;
|
|
8
|
+
export declare function humanizeIdentifier(value: string): string;
|
|
9
|
+
export declare function parseAtlasUnitValue(input: string, location?: AstSourceLocation, fieldKey?: string): UnitValue;
|
|
10
|
+
export declare function tryParseAtlasUnitValue(input: string): UnitValue | null;
|
|
11
|
+
export declare function parseAtlasNumber(input: string, key: string, location?: AstSourceLocation): number;
|
|
12
|
+
export declare function parseAtlasBoolean(input: string, key: string, location?: AstSourceLocation): boolean;
|
|
13
|
+
export declare function parseAtlasFieldBoolean(field: AtlasFieldLike): boolean;
|
|
14
|
+
export declare function parseAtlasAtReference(target: string, location?: AstSourceLocation): AtReference;
|
|
15
|
+
export declare function validateAtlasImageSource(value: string, location?: AstSourceLocation): void;
|
|
16
|
+
export declare function normalizeLegacyScalarValue(key: string, values: string[], location: AstSourceLocation): NormalizedValue;
|
|
17
|
+
export declare function ensureAtlasFieldSupported(key: string, objectType: WorldOrbitObjectType, location: AstSourceLocation): void;
|
|
18
|
+
export declare function singleAtlasFieldValue(field: Pick<AtlasFieldLike, "key" | "values" | "location">): string;
|
|
19
|
+
export declare function singleAtlasValue(values: string[], key: string, location?: AstSourceLocation): string;
|
|
20
|
+
export declare function isStructureLikeObjectType(objectType: WorldOrbitObjectType): boolean;
|
|
21
|
+
export declare function cloneNormalizedValue(value: NormalizedValue): NormalizedValue;
|
|
22
|
+
export declare function cloneFieldNode(field: AstFieldNode): AstFieldNode;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { WorldOrbitError } from "./errors.js";
|
|
2
|
+
import { getFieldSchema, unitFamilyAllowsUnit } from "./schema.js";
|
|
3
|
+
const UNIT_PATTERN = /^(-?\d+(?:\.\d+)?)(kpc|min|mj|rj|ky|my|gy|au|km|me|re|pc|ly|deg|sol|K|m|s|h|d|y)?$/;
|
|
4
|
+
const BOOLEAN_VALUES = new Map([
|
|
5
|
+
["true", true],
|
|
6
|
+
["false", false],
|
|
7
|
+
["yes", true],
|
|
8
|
+
["no", false],
|
|
9
|
+
]);
|
|
10
|
+
const URL_SCHEME_PATTERN = /^[A-Za-z][A-Za-z0-9+.-]*:/;
|
|
11
|
+
export function normalizeIdentifier(value) {
|
|
12
|
+
return value
|
|
13
|
+
.trim()
|
|
14
|
+
.toLowerCase()
|
|
15
|
+
.replace(/[^a-z0-9_-]+/g, "-")
|
|
16
|
+
.replace(/^-+|-+$/g, "");
|
|
17
|
+
}
|
|
18
|
+
export function humanizeIdentifier(value) {
|
|
19
|
+
return value
|
|
20
|
+
.split(/[-_]+/)
|
|
21
|
+
.filter(Boolean)
|
|
22
|
+
.map((segment) => segment[0].toUpperCase() + segment.slice(1))
|
|
23
|
+
.join(" ");
|
|
24
|
+
}
|
|
25
|
+
export function parseAtlasUnitValue(input, location, fieldKey) {
|
|
26
|
+
const match = input.match(UNIT_PATTERN);
|
|
27
|
+
if (!match) {
|
|
28
|
+
throw WorldOrbitError.fromLocation(`Invalid unit value "${input}"`, location);
|
|
29
|
+
}
|
|
30
|
+
const unitValue = {
|
|
31
|
+
value: Number(match[1]),
|
|
32
|
+
unit: match[2] ?? null,
|
|
33
|
+
};
|
|
34
|
+
if (fieldKey) {
|
|
35
|
+
const schema = getFieldSchema(fieldKey);
|
|
36
|
+
if (schema?.unitFamily && !unitFamilyAllowsUnit(schema.unitFamily, unitValue.unit)) {
|
|
37
|
+
throw WorldOrbitError.fromLocation(`Unit "${unitValue.unit ?? "none"}" is not valid for "${fieldKey}"`, location);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return unitValue;
|
|
41
|
+
}
|
|
42
|
+
export function tryParseAtlasUnitValue(input) {
|
|
43
|
+
const match = input.match(UNIT_PATTERN);
|
|
44
|
+
if (!match) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
value: Number(match[1]),
|
|
49
|
+
unit: match[2] ?? null,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export function parseAtlasNumber(input, key, location) {
|
|
53
|
+
const value = Number(input);
|
|
54
|
+
if (!Number.isFinite(value)) {
|
|
55
|
+
throw WorldOrbitError.fromLocation(`Invalid numeric value "${input}" for "${key}"`, location);
|
|
56
|
+
}
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
export function parseAtlasBoolean(input, key, location) {
|
|
60
|
+
const parsed = BOOLEAN_VALUES.get(input.toLowerCase());
|
|
61
|
+
if (parsed === undefined) {
|
|
62
|
+
throw WorldOrbitError.fromLocation(`Invalid boolean value "${input}" for "${key}"`, location);
|
|
63
|
+
}
|
|
64
|
+
return parsed;
|
|
65
|
+
}
|
|
66
|
+
export function parseAtlasFieldBoolean(field) {
|
|
67
|
+
return parseAtlasBoolean(singleAtlasFieldValue(field), field.key, field.location);
|
|
68
|
+
}
|
|
69
|
+
export function parseAtlasAtReference(target, location) {
|
|
70
|
+
if (/^[A-Za-z0-9._-]+-[A-Za-z0-9._-]+:L\d+$/i.test(target)) {
|
|
71
|
+
throw WorldOrbitError.fromLocation(`Invalid special position "${target}"`, location);
|
|
72
|
+
}
|
|
73
|
+
const pairedMatch = target.match(/^([A-Za-z0-9._-]+)-([A-Za-z0-9._-]+):(L[1-5])$/);
|
|
74
|
+
if (pairedMatch) {
|
|
75
|
+
return {
|
|
76
|
+
kind: "lagrange",
|
|
77
|
+
primary: pairedMatch[1],
|
|
78
|
+
secondary: pairedMatch[2],
|
|
79
|
+
point: pairedMatch[3],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const simpleMatch = target.match(/^([A-Za-z0-9._-]+):(L[1-5])$/);
|
|
83
|
+
if (simpleMatch) {
|
|
84
|
+
return {
|
|
85
|
+
kind: "lagrange",
|
|
86
|
+
primary: simpleMatch[1],
|
|
87
|
+
secondary: null,
|
|
88
|
+
point: simpleMatch[2],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
if (/^[A-Za-z0-9._-]+:L\d+$/i.test(target)) {
|
|
92
|
+
throw WorldOrbitError.fromLocation(`Invalid special position "${target}"`, location);
|
|
93
|
+
}
|
|
94
|
+
const anchorMatch = target.match(/^([A-Za-z0-9._-]+):([A-Za-z0-9._-]+)$/);
|
|
95
|
+
if (anchorMatch) {
|
|
96
|
+
return {
|
|
97
|
+
kind: "anchor",
|
|
98
|
+
objectId: anchorMatch[1],
|
|
99
|
+
anchor: anchorMatch[2],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
kind: "named",
|
|
104
|
+
name: target,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
export function validateAtlasImageSource(value, location) {
|
|
108
|
+
if (!value) {
|
|
109
|
+
throw WorldOrbitError.fromLocation('Field "image" must not be empty', location);
|
|
110
|
+
}
|
|
111
|
+
if (value.startsWith("//")) {
|
|
112
|
+
throw WorldOrbitError.fromLocation('Field "image" must use a relative path, root-relative path, or an http/https URL', location);
|
|
113
|
+
}
|
|
114
|
+
const schemeMatch = value.match(URL_SCHEME_PATTERN);
|
|
115
|
+
if (!schemeMatch) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const scheme = schemeMatch[0].slice(0, -1).toLowerCase();
|
|
119
|
+
if (scheme !== "http" && scheme !== "https") {
|
|
120
|
+
throw WorldOrbitError.fromLocation(`Field "image" does not support the "${scheme}" scheme`, location);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
export function normalizeLegacyScalarValue(key, values, location) {
|
|
124
|
+
const schema = getFieldSchema(key);
|
|
125
|
+
if (!schema) {
|
|
126
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${key}"`, location);
|
|
127
|
+
}
|
|
128
|
+
if (schema.arity === "single" && values.length !== 1) {
|
|
129
|
+
throw WorldOrbitError.fromLocation(`Field "${key}" expects exactly one value`, location);
|
|
130
|
+
}
|
|
131
|
+
switch (schema.kind) {
|
|
132
|
+
case "list":
|
|
133
|
+
return values;
|
|
134
|
+
case "boolean":
|
|
135
|
+
return parseAtlasBoolean(singleAtlasValue(values, key, location), key, location);
|
|
136
|
+
case "number":
|
|
137
|
+
return parseAtlasNumber(singleAtlasValue(values, key, location), key, location);
|
|
138
|
+
case "unit":
|
|
139
|
+
return parseAtlasUnitValue(singleAtlasValue(values, key, location), location, key);
|
|
140
|
+
case "string": {
|
|
141
|
+
const value = values.join(" ").trim();
|
|
142
|
+
if (key === "image") {
|
|
143
|
+
validateAtlasImageSource(value, location);
|
|
144
|
+
}
|
|
145
|
+
return value;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
export function ensureAtlasFieldSupported(key, objectType, location) {
|
|
150
|
+
const schema = getFieldSchema(key);
|
|
151
|
+
if (!schema) {
|
|
152
|
+
throw WorldOrbitError.fromLocation(`Unknown field "${key}"`, location);
|
|
153
|
+
}
|
|
154
|
+
if (!schema.objectTypes.includes(objectType)) {
|
|
155
|
+
throw WorldOrbitError.fromLocation(`Field "${key}" is not valid on "${objectType}"`, location);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
export function singleAtlasFieldValue(field) {
|
|
159
|
+
return singleAtlasValue(field.values, field.key, field.location);
|
|
160
|
+
}
|
|
161
|
+
export function singleAtlasValue(values, key, location) {
|
|
162
|
+
if (values.length !== 1) {
|
|
163
|
+
throw WorldOrbitError.fromLocation(`Field "${key}" expects exactly one value`, location);
|
|
164
|
+
}
|
|
165
|
+
return values[0];
|
|
166
|
+
}
|
|
167
|
+
export function isStructureLikeObjectType(objectType) {
|
|
168
|
+
return objectType === "structure" || objectType === "phenomenon";
|
|
169
|
+
}
|
|
170
|
+
export function cloneNormalizedValue(value) {
|
|
171
|
+
if (Array.isArray(value)) {
|
|
172
|
+
return [...value];
|
|
173
|
+
}
|
|
174
|
+
if (value && typeof value === "object" && "value" in value) {
|
|
175
|
+
return {
|
|
176
|
+
value: value.value,
|
|
177
|
+
unit: value.unit,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return value;
|
|
181
|
+
}
|
|
182
|
+
export function cloneFieldNode(field) {
|
|
183
|
+
return {
|
|
184
|
+
type: "field",
|
|
185
|
+
key: field.key,
|
|
186
|
+
values: [...field.values],
|
|
187
|
+
location: { ...field.location },
|
|
188
|
+
};
|
|
189
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import type { WorldOrbitAnyDocumentVersion, WorldOrbitAtlasDocument, WorldOrbitDiagnostic, WorldOrbitDraftDocument } from "./types.js";
|
|
2
|
+
export declare function collectAtlasDiagnostics(document: WorldOrbitAtlasDocument | WorldOrbitDraftDocument, sourceSchemaVersion?: WorldOrbitAnyDocumentVersion): WorldOrbitDiagnostic[];
|