worldorbit 2.5.2

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.
Files changed (113) hide show
  1. package/LICENSE.md +5 -0
  2. package/README.md +250 -0
  3. package/dist/browser/core/dist/index.js +4009 -0
  4. package/dist/browser/markdown/dist/index.js +3951 -0
  5. package/dist/browser/viewer/dist/index.js +5981 -0
  6. package/dist/constants.d.ts +8 -0
  7. package/dist/constants.js +84 -0
  8. package/dist/errors.d.ts +7 -0
  9. package/dist/errors.js +16 -0
  10. package/dist/index.d.ts +18 -0
  11. package/dist/index.js +25 -0
  12. package/dist/normalize.d.ts +2 -0
  13. package/dist/normalize.js +243 -0
  14. package/dist/parse.d.ts +2 -0
  15. package/dist/parse.js +126 -0
  16. package/dist/render.d.ts +6 -0
  17. package/dist/render.js +683 -0
  18. package/dist/tokenize.d.ts +4 -0
  19. package/dist/tokenize.js +68 -0
  20. package/dist/types.d.ts +208 -0
  21. package/dist/types.js +1 -0
  22. package/dist/unpkg/core/dist/index.js +4081 -0
  23. package/dist/unpkg/markdown/dist/index.js +3979 -0
  24. package/dist/unpkg/test.html +1 -0
  25. package/dist/unpkg/viewer/dist/index.js +6038 -0
  26. package/dist/unpkg/worldorbit-core.min.js +5 -0
  27. package/dist/unpkg/worldorbit-markdown.min.js +81 -0
  28. package/dist/unpkg/worldorbit-viewer.min.js +232 -0
  29. package/dist/unpkg/worldorbit.d.ts +2 -0
  30. package/dist/unpkg/worldorbit.js +2 -0
  31. package/dist/unpkg/worldorbit.min.js +236 -0
  32. package/dist/validate.d.ts +2 -0
  33. package/dist/validate.js +31 -0
  34. package/dist/viewer-state.d.ts +16 -0
  35. package/dist/viewer-state.js +130 -0
  36. package/dist/viewer.d.ts +2 -0
  37. package/dist/viewer.js +434 -0
  38. package/package.json +64 -0
  39. package/packages/core/README.md +13 -0
  40. package/packages/core/dist/atlas-edit.d.ts +11 -0
  41. package/packages/core/dist/atlas-edit.js +210 -0
  42. package/packages/core/dist/diagnostics.d.ts +10 -0
  43. package/packages/core/dist/diagnostics.js +109 -0
  44. package/packages/core/dist/draft-parse.d.ts +3 -0
  45. package/packages/core/dist/draft-parse.js +642 -0
  46. package/packages/core/dist/draft.d.ts +15 -0
  47. package/packages/core/dist/draft.js +343 -0
  48. package/packages/core/dist/errors.d.ts +7 -0
  49. package/packages/core/dist/errors.js +16 -0
  50. package/packages/core/dist/format.d.ts +4 -0
  51. package/packages/core/dist/format.js +364 -0
  52. package/packages/core/dist/index.d.ts +28 -0
  53. package/packages/core/dist/index.js +44 -0
  54. package/packages/core/dist/load.d.ts +4 -0
  55. package/packages/core/dist/load.js +130 -0
  56. package/packages/core/dist/markdown.d.ts +2 -0
  57. package/packages/core/dist/markdown.js +37 -0
  58. package/packages/core/dist/normalize.d.ts +2 -0
  59. package/packages/core/dist/normalize.js +304 -0
  60. package/packages/core/dist/parse.d.ts +2 -0
  61. package/packages/core/dist/parse.js +133 -0
  62. package/packages/core/dist/scene.d.ts +3 -0
  63. package/packages/core/dist/scene.js +1484 -0
  64. package/packages/core/dist/schema.d.ts +8 -0
  65. package/packages/core/dist/schema.js +298 -0
  66. package/packages/core/dist/tokenize.d.ts +4 -0
  67. package/packages/core/dist/tokenize.js +68 -0
  68. package/packages/core/dist/types.d.ts +382 -0
  69. package/packages/core/dist/types.js +1 -0
  70. package/packages/core/dist/validate.d.ts +2 -0
  71. package/packages/core/dist/validate.js +56 -0
  72. package/packages/editor/dist/editor.d.ts +2 -0
  73. package/packages/editor/dist/editor.js +2620 -0
  74. package/packages/editor/dist/index.d.ts +2 -0
  75. package/packages/editor/dist/index.js +1 -0
  76. package/packages/editor/dist/types.d.ts +53 -0
  77. package/packages/editor/dist/types.js +1 -0
  78. package/packages/markdown/README.md +9 -0
  79. package/packages/markdown/dist/html.d.ts +3 -0
  80. package/packages/markdown/dist/html.js +57 -0
  81. package/packages/markdown/dist/index.d.ts +4 -0
  82. package/packages/markdown/dist/index.js +3 -0
  83. package/packages/markdown/dist/rehype.d.ts +10 -0
  84. package/packages/markdown/dist/rehype.js +49 -0
  85. package/packages/markdown/dist/remark.d.ts +9 -0
  86. package/packages/markdown/dist/remark.js +28 -0
  87. package/packages/markdown/dist/types.d.ts +11 -0
  88. package/packages/markdown/dist/types.js +1 -0
  89. package/packages/viewer/README.md +12 -0
  90. package/packages/viewer/dist/atlas-state.d.ts +12 -0
  91. package/packages/viewer/dist/atlas-state.js +251 -0
  92. package/packages/viewer/dist/atlas-viewer.d.ts +2 -0
  93. package/packages/viewer/dist/atlas-viewer.js +448 -0
  94. package/packages/viewer/dist/custom-element.d.ts +1 -0
  95. package/packages/viewer/dist/custom-element.js +64 -0
  96. package/packages/viewer/dist/embed.d.ts +20 -0
  97. package/packages/viewer/dist/embed.js +138 -0
  98. package/packages/viewer/dist/index.d.ts +9 -0
  99. package/packages/viewer/dist/index.js +8 -0
  100. package/packages/viewer/dist/minimap.d.ts +3 -0
  101. package/packages/viewer/dist/minimap.js +63 -0
  102. package/packages/viewer/dist/render.d.ts +6 -0
  103. package/packages/viewer/dist/render.js +585 -0
  104. package/packages/viewer/dist/theme.d.ts +4 -0
  105. package/packages/viewer/dist/theme.js +98 -0
  106. package/packages/viewer/dist/tooltip.d.ts +3 -0
  107. package/packages/viewer/dist/tooltip.js +154 -0
  108. package/packages/viewer/dist/types.d.ts +256 -0
  109. package/packages/viewer/dist/types.js +1 -0
  110. package/packages/viewer/dist/viewer-state.d.ts +19 -0
  111. package/packages/viewer/dist/viewer-state.js +162 -0
  112. package/packages/viewer/dist/viewer.d.ts +2 -0
  113. package/packages/viewer/dist/viewer.js +1156 -0
@@ -0,0 +1,642 @@
1
+ import { WorldOrbitError } from "./errors.js";
2
+ import { normalizeDocument } from "./normalize.js";
3
+ import { getFieldSchema, isKnownFieldKey, WORLDORBIT_OBJECT_TYPES } from "./schema.js";
4
+ import { getIndent, tokenizeLineDetailed } from "./tokenize.js";
5
+ import { validateDocument } from "./validate.js";
6
+ export function parseWorldOrbitAtlas(source) {
7
+ return parseAtlasSource(source, "2.0");
8
+ }
9
+ export function parseWorldOrbitDraft(source) {
10
+ return parseAtlasSource(source, "2.0-draft");
11
+ }
12
+ function parseAtlasSource(source, outputVersion) {
13
+ const lines = source.split(/\r?\n/);
14
+ let sawSchemaHeader = false;
15
+ let schemaVersion = "2.0";
16
+ let system = null;
17
+ let section = null;
18
+ const objectNodes = [];
19
+ let sawDefaults = false;
20
+ let sawAtlas = false;
21
+ const viewpointIds = new Set();
22
+ const annotationIds = new Set();
23
+ for (let index = 0; index < lines.length; index++) {
24
+ const rawLine = lines[index];
25
+ const lineNumber = index + 1;
26
+ if (!rawLine.trim()) {
27
+ continue;
28
+ }
29
+ const indent = getIndent(rawLine);
30
+ const tokens = tokenizeLineDetailed(rawLine.slice(indent), {
31
+ line: lineNumber,
32
+ columnOffset: indent,
33
+ });
34
+ if (tokens.length === 0) {
35
+ continue;
36
+ }
37
+ if (!sawSchemaHeader) {
38
+ schemaVersion = assertDraftSchemaHeader(tokens, lineNumber);
39
+ sawSchemaHeader = true;
40
+ continue;
41
+ }
42
+ if (indent === 0) {
43
+ section = startTopLevelSection(tokens, lineNumber, system, objectNodes, viewpointIds, annotationIds, {
44
+ sawDefaults,
45
+ sawAtlas,
46
+ });
47
+ if (section.kind === "system") {
48
+ system = section.system;
49
+ }
50
+ else if (section.kind === "defaults") {
51
+ sawDefaults = true;
52
+ }
53
+ else if (section.kind === "atlas") {
54
+ sawAtlas = true;
55
+ }
56
+ continue;
57
+ }
58
+ if (!section) {
59
+ throw new WorldOrbitError("Indented line without parent atlas section", lineNumber, indent + 1);
60
+ }
61
+ handleSectionLine(section, indent, tokens, lineNumber);
62
+ }
63
+ if (!sawSchemaHeader) {
64
+ throw new WorldOrbitError('Missing required atlas schema header "schema 2.0"');
65
+ }
66
+ const ast = {
67
+ type: "document",
68
+ objects: objectNodes,
69
+ };
70
+ const normalizedObjects = normalizeDocument(ast).objects;
71
+ validateDocument({
72
+ format: "worldorbit",
73
+ version: "1.0",
74
+ system: null,
75
+ objects: normalizedObjects,
76
+ });
77
+ const diagnostics = schemaVersion === "2.0-draft" && outputVersion === "2.0"
78
+ ? [
79
+ {
80
+ code: "load.schema.deprecatedDraft",
81
+ severity: "warning",
82
+ source: "upgrade",
83
+ message: 'Source header "schema 2.0-draft" is deprecated; canonical v2 documents now use "schema 2.0".',
84
+ },
85
+ ]
86
+ : [];
87
+ return {
88
+ format: "worldorbit",
89
+ version: outputVersion,
90
+ sourceVersion: "1.0",
91
+ system,
92
+ objects: normalizedObjects,
93
+ diagnostics,
94
+ };
95
+ }
96
+ function assertDraftSchemaHeader(tokens, line) {
97
+ if (tokens.length !== 2 ||
98
+ tokens[0].value.toLowerCase() !== "schema" ||
99
+ (tokens[1].value.toLowerCase() !== "2.0-draft" &&
100
+ tokens[1].value.toLowerCase() !== "2.0")) {
101
+ throw new WorldOrbitError('Expected atlas header "schema 2.0" or legacy "schema 2.0-draft"', line, tokens[0]?.column ?? 1);
102
+ }
103
+ return tokens[1].value.toLowerCase() === "2.0-draft" ? "2.0-draft" : "2.0";
104
+ }
105
+ function startTopLevelSection(tokens, line, system, objectNodes, viewpointIds, annotationIds, flags) {
106
+ const keyword = tokens[0]?.value.toLowerCase();
107
+ switch (keyword) {
108
+ case "system":
109
+ if (system) {
110
+ throw new WorldOrbitError('Atlas section "system" may only appear once', line, tokens[0].column);
111
+ }
112
+ return startSystemSection(tokens, line);
113
+ case "defaults":
114
+ if (!system) {
115
+ throw new WorldOrbitError('Atlas section "defaults" requires a preceding system declaration', line, tokens[0].column);
116
+ }
117
+ if (flags.sawDefaults) {
118
+ throw new WorldOrbitError('Atlas section "defaults" may only appear once', line, tokens[0].column);
119
+ }
120
+ return {
121
+ kind: "defaults",
122
+ system,
123
+ seenFields: new Set(),
124
+ };
125
+ case "atlas":
126
+ if (!system) {
127
+ throw new WorldOrbitError('Atlas section "atlas" requires a preceding system declaration', line, tokens[0].column);
128
+ }
129
+ if (flags.sawAtlas) {
130
+ throw new WorldOrbitError('Atlas section "atlas" may only appear once', line, tokens[0].column);
131
+ }
132
+ return {
133
+ kind: "atlas",
134
+ system,
135
+ inMetadata: false,
136
+ metadataIndent: null,
137
+ };
138
+ case "viewpoint":
139
+ if (!system) {
140
+ throw new WorldOrbitError('Atlas section "viewpoint" requires a preceding system declaration', line, tokens[0].column);
141
+ }
142
+ return startViewpointSection(tokens, line, system, viewpointIds);
143
+ case "annotation":
144
+ if (!system) {
145
+ throw new WorldOrbitError('Atlas section "annotation" requires a preceding system declaration', line, tokens[0].column);
146
+ }
147
+ return startAnnotationSection(tokens, line, system, annotationIds);
148
+ case "object":
149
+ return startObjectSection(tokens, line, objectNodes);
150
+ default:
151
+ throw new WorldOrbitError(`Unknown atlas section "${tokens[0]?.value ?? ""}"`, line, tokens[0]?.column ?? 1);
152
+ }
153
+ }
154
+ function startSystemSection(tokens, line) {
155
+ if (tokens.length !== 2) {
156
+ throw new WorldOrbitError("Invalid atlas system declaration", line, tokens[0]?.column ?? 1);
157
+ }
158
+ const system = {
159
+ type: "system",
160
+ id: tokens[1].value,
161
+ title: null,
162
+ defaults: {
163
+ view: "topdown",
164
+ scale: null,
165
+ units: null,
166
+ preset: null,
167
+ theme: null,
168
+ },
169
+ atlasMetadata: {},
170
+ viewpoints: [],
171
+ annotations: [],
172
+ };
173
+ return {
174
+ kind: "system",
175
+ system,
176
+ seenFields: new Set(),
177
+ };
178
+ }
179
+ function startViewpointSection(tokens, line, system, viewpointIds) {
180
+ if (tokens.length !== 2) {
181
+ throw new WorldOrbitError("Invalid viewpoint declaration", line, tokens[0]?.column ?? 1);
182
+ }
183
+ const id = normalizeIdentifier(tokens[1].value);
184
+ if (!id) {
185
+ throw new WorldOrbitError("Viewpoint id must not be empty", line, tokens[1].column);
186
+ }
187
+ if (viewpointIds.has(id)) {
188
+ throw new WorldOrbitError(`Duplicate viewpoint id "${id}"`, line, tokens[1].column);
189
+ }
190
+ const viewpoint = {
191
+ id,
192
+ label: humanizeIdentifier(id),
193
+ summary: "",
194
+ focusObjectId: null,
195
+ selectedObjectId: null,
196
+ projection: system.defaults.view,
197
+ preset: system.defaults.preset,
198
+ zoom: null,
199
+ rotationDeg: 0,
200
+ layers: {},
201
+ filter: null,
202
+ };
203
+ system.viewpoints.push(viewpoint);
204
+ viewpointIds.add(id);
205
+ return {
206
+ kind: "viewpoint",
207
+ viewpoint,
208
+ seenFields: new Set(),
209
+ inFilter: false,
210
+ filterIndent: null,
211
+ seenFilterFields: new Set(),
212
+ };
213
+ }
214
+ function startAnnotationSection(tokens, line, system, annotationIds) {
215
+ if (tokens.length !== 2) {
216
+ throw new WorldOrbitError("Invalid annotation declaration", line, tokens[0]?.column ?? 1);
217
+ }
218
+ const id = normalizeIdentifier(tokens[1].value);
219
+ if (!id) {
220
+ throw new WorldOrbitError("Annotation id must not be empty", line, tokens[1].column);
221
+ }
222
+ if (annotationIds.has(id)) {
223
+ throw new WorldOrbitError(`Duplicate annotation id "${id}"`, line, tokens[1].column);
224
+ }
225
+ const annotation = {
226
+ id,
227
+ label: humanizeIdentifier(id),
228
+ targetObjectId: null,
229
+ body: "",
230
+ tags: [],
231
+ sourceObjectId: null,
232
+ };
233
+ system.annotations.push(annotation);
234
+ annotationIds.add(id);
235
+ return {
236
+ kind: "annotation",
237
+ annotation,
238
+ seenFields: new Set(),
239
+ };
240
+ }
241
+ function startObjectSection(tokens, line, objectNodes) {
242
+ if (tokens.length < 3) {
243
+ throw new WorldOrbitError("Invalid atlas object declaration", line, tokens[0]?.column ?? 1);
244
+ }
245
+ const objectTypeToken = tokens[1];
246
+ const idToken = tokens[2];
247
+ const objectType = objectTypeToken.value;
248
+ if (!WORLDORBIT_OBJECT_TYPES.has(objectType) ||
249
+ objectType === "system") {
250
+ throw new WorldOrbitError(`Unknown object type "${objectTypeToken.value}"`, line, objectTypeToken.column);
251
+ }
252
+ const objectNode = {
253
+ type: "object",
254
+ objectType,
255
+ name: idToken.value,
256
+ inlineFields: parseInlineFields(tokens.slice(3), line),
257
+ blockFields: [],
258
+ infoEntries: [],
259
+ location: {
260
+ line,
261
+ column: objectTypeToken.column,
262
+ },
263
+ };
264
+ objectNodes.push(objectNode);
265
+ return {
266
+ kind: "object",
267
+ objectNode,
268
+ inInfoBlock: false,
269
+ infoIndent: null,
270
+ };
271
+ }
272
+ function handleSectionLine(section, indent, tokens, line) {
273
+ switch (section.kind) {
274
+ case "system":
275
+ applySystemField(section, tokens, line);
276
+ return;
277
+ case "defaults":
278
+ applyDefaultsField(section, tokens, line);
279
+ return;
280
+ case "atlas":
281
+ applyAtlasField(section, indent, tokens, line);
282
+ return;
283
+ case "viewpoint":
284
+ applyViewpointField(section, indent, tokens, line);
285
+ return;
286
+ case "annotation":
287
+ applyAnnotationField(section, tokens, line);
288
+ return;
289
+ case "object":
290
+ applyObjectField(section, indent, tokens, line);
291
+ return;
292
+ }
293
+ }
294
+ function applySystemField(section, tokens, line) {
295
+ const key = requireUniqueField(tokens, section.seenFields, line);
296
+ if (key !== "title") {
297
+ throw new WorldOrbitError(`Unknown system atlas field "${tokens[0].value}"`, line, tokens[0].column);
298
+ }
299
+ section.system.title = joinFieldValue(tokens, line);
300
+ }
301
+ function applyDefaultsField(section, tokens, line) {
302
+ const key = requireUniqueField(tokens, section.seenFields, line);
303
+ const value = joinFieldValue(tokens, line);
304
+ switch (key) {
305
+ case "view":
306
+ section.system.defaults.view = parseProjectionValue(value, line, tokens[0].column);
307
+ return;
308
+ case "scale":
309
+ section.system.defaults.scale = value;
310
+ return;
311
+ case "units":
312
+ section.system.defaults.units = value;
313
+ return;
314
+ case "preset":
315
+ section.system.defaults.preset = parsePresetValue(value, line, tokens[0].column);
316
+ return;
317
+ case "theme":
318
+ section.system.defaults.theme = value;
319
+ return;
320
+ default:
321
+ throw new WorldOrbitError(`Unknown defaults field "${tokens[0].value}"`, line, tokens[0].column);
322
+ }
323
+ }
324
+ function applyAtlasField(section, indent, tokens, line) {
325
+ if (section.inMetadata && indent <= (section.metadataIndent ?? 0)) {
326
+ section.inMetadata = false;
327
+ section.metadataIndent = null;
328
+ }
329
+ if (section.inMetadata) {
330
+ if (tokens.length < 2) {
331
+ throw new WorldOrbitError("Invalid atlas metadata entry", line, tokens[0]?.column ?? 1);
332
+ }
333
+ const key = tokens[0].value;
334
+ if (key in section.system.atlasMetadata) {
335
+ throw new WorldOrbitError(`Duplicate atlas metadata key "${key}"`, line, tokens[0].column);
336
+ }
337
+ section.system.atlasMetadata[key] = joinFieldValue(tokens, line);
338
+ return;
339
+ }
340
+ if (tokens.length === 1 && tokens[0].value.toLowerCase() === "metadata") {
341
+ section.inMetadata = true;
342
+ section.metadataIndent = indent;
343
+ return;
344
+ }
345
+ throw new WorldOrbitError(`Unknown atlas field "${tokens[0].value}"`, line, tokens[0].column);
346
+ }
347
+ function applyViewpointField(section, indent, tokens, line) {
348
+ if (section.inFilter && indent <= (section.filterIndent ?? 0)) {
349
+ section.inFilter = false;
350
+ section.filterIndent = null;
351
+ }
352
+ if (section.inFilter) {
353
+ applyViewpointFilterField(section, tokens, line);
354
+ return;
355
+ }
356
+ if (tokens.length === 1 && tokens[0].value.toLowerCase() === "filter") {
357
+ if (section.seenFields.has("filter")) {
358
+ throw new WorldOrbitError('Duplicate viewpoint field "filter"', line, tokens[0].column);
359
+ }
360
+ section.seenFields.add("filter");
361
+ section.inFilter = true;
362
+ section.filterIndent = indent;
363
+ return;
364
+ }
365
+ const key = requireUniqueField(tokens, section.seenFields, line);
366
+ const value = joinFieldValue(tokens, line);
367
+ switch (key) {
368
+ case "label":
369
+ section.viewpoint.label = value;
370
+ return;
371
+ case "summary":
372
+ section.viewpoint.summary = value;
373
+ return;
374
+ case "focus":
375
+ section.viewpoint.focusObjectId = value;
376
+ return;
377
+ case "select":
378
+ section.viewpoint.selectedObjectId = value;
379
+ return;
380
+ case "projection":
381
+ section.viewpoint.projection = parseProjectionValue(value, line, tokens[0].column);
382
+ return;
383
+ case "preset":
384
+ section.viewpoint.preset = parsePresetValue(value, line, tokens[0].column);
385
+ return;
386
+ case "zoom":
387
+ section.viewpoint.zoom = parsePositiveNumber(value, line, tokens[0].column, "zoom");
388
+ return;
389
+ case "rotation":
390
+ section.viewpoint.rotationDeg = parseFiniteNumber(value, line, tokens[0].column, "rotation");
391
+ return;
392
+ case "layers":
393
+ section.viewpoint.layers = parseLayerTokens(tokens.slice(1), line);
394
+ return;
395
+ default:
396
+ throw new WorldOrbitError(`Unknown viewpoint field "${tokens[0].value}"`, line, tokens[0].column);
397
+ }
398
+ }
399
+ function applyViewpointFilterField(section, tokens, line) {
400
+ const key = requireUniqueField(tokens, section.seenFilterFields, line);
401
+ const filter = section.viewpoint.filter ?? createEmptyViewpointFilter();
402
+ switch (key) {
403
+ case "query":
404
+ filter.query = joinFieldValue(tokens, line);
405
+ break;
406
+ case "objecttypes":
407
+ filter.objectTypes = parseObjectTypeTokens(tokens.slice(1), line);
408
+ break;
409
+ case "tags":
410
+ filter.tags = parseTokenList(tokens.slice(1), line, "tags");
411
+ break;
412
+ case "groups":
413
+ filter.groupIds = parseTokenList(tokens.slice(1), line, "groups");
414
+ break;
415
+ default:
416
+ throw new WorldOrbitError(`Unknown viewpoint filter field "${tokens[0].value}"`, line, tokens[0].column);
417
+ }
418
+ section.viewpoint.filter = filter;
419
+ }
420
+ function applyAnnotationField(section, tokens, line) {
421
+ const key = requireUniqueField(tokens, section.seenFields, line);
422
+ switch (key) {
423
+ case "label":
424
+ section.annotation.label = joinFieldValue(tokens, line);
425
+ return;
426
+ case "target":
427
+ section.annotation.targetObjectId = joinFieldValue(tokens, line);
428
+ return;
429
+ case "body":
430
+ section.annotation.body = joinFieldValue(tokens, line);
431
+ return;
432
+ case "tags":
433
+ section.annotation.tags = parseTokenList(tokens.slice(1), line, "tags");
434
+ return;
435
+ default:
436
+ throw new WorldOrbitError(`Unknown annotation field "${tokens[0].value}"`, line, tokens[0].column);
437
+ }
438
+ }
439
+ function applyObjectField(section, indent, tokens, line) {
440
+ if (tokens.length === 1 && tokens[0].value === "info") {
441
+ section.inInfoBlock = true;
442
+ section.infoIndent = indent;
443
+ return;
444
+ }
445
+ if (section.inInfoBlock && indent <= (section.infoIndent ?? 0)) {
446
+ section.inInfoBlock = false;
447
+ section.infoIndent = null;
448
+ }
449
+ if (section.inInfoBlock) {
450
+ section.objectNode.infoEntries.push(parseInfoEntry(tokens, line));
451
+ return;
452
+ }
453
+ section.objectNode.blockFields.push(parseField(tokens, line));
454
+ }
455
+ function requireUniqueField(tokens, seenFields, line) {
456
+ if (tokens.length < 2) {
457
+ throw new WorldOrbitError("Invalid atlas field line", line, tokens[0]?.column ?? 1);
458
+ }
459
+ const key = tokens[0].value.toLowerCase();
460
+ if (seenFields.has(key)) {
461
+ throw new WorldOrbitError(`Duplicate atlas field "${tokens[0].value}"`, line, tokens[0].column);
462
+ }
463
+ seenFields.add(key);
464
+ return key;
465
+ }
466
+ function joinFieldValue(tokens, line) {
467
+ if (tokens.length < 2) {
468
+ throw new WorldOrbitError("Missing value for atlas field", line, tokens[0]?.column ?? 1);
469
+ }
470
+ return tokens
471
+ .slice(1)
472
+ .map((token) => token.value)
473
+ .join(" ")
474
+ .trim();
475
+ }
476
+ function parseObjectTypeTokens(tokens, line) {
477
+ if (tokens.length === 0) {
478
+ throw new WorldOrbitError("Missing value for atlas field", line);
479
+ }
480
+ return tokens.map((token) => {
481
+ const value = token.value;
482
+ if (value !== "star" &&
483
+ value !== "planet" &&
484
+ value !== "moon" &&
485
+ value !== "belt" &&
486
+ value !== "asteroid" &&
487
+ value !== "comet" &&
488
+ value !== "ring" &&
489
+ value !== "structure" &&
490
+ value !== "phenomenon") {
491
+ throw new WorldOrbitError(`Unknown viewpoint object type "${token.value}"`, line, token.column);
492
+ }
493
+ return value;
494
+ });
495
+ }
496
+ function parseTokenList(tokens, line, field) {
497
+ if (tokens.length === 0) {
498
+ throw new WorldOrbitError(`Missing value for field "${field}"`, line);
499
+ }
500
+ return tokens.map((token) => token.value);
501
+ }
502
+ function parseLayerTokens(tokens, line) {
503
+ if (tokens.length === 0) {
504
+ throw new WorldOrbitError('Missing value for field "layers"', line);
505
+ }
506
+ const next = {};
507
+ for (const token of tokens) {
508
+ const enabled = !token.value.startsWith("-") && !token.value.startsWith("!");
509
+ const rawLayer = token.value.replace(/^[-!]+/, "").toLowerCase();
510
+ if (rawLayer === "orbits") {
511
+ next["orbits-back"] = enabled;
512
+ next["orbits-front"] = enabled;
513
+ continue;
514
+ }
515
+ if (rawLayer === "background" ||
516
+ rawLayer === "guides" ||
517
+ rawLayer === "orbits-back" ||
518
+ rawLayer === "orbits-front" ||
519
+ rawLayer === "objects" ||
520
+ rawLayer === "labels" ||
521
+ rawLayer === "metadata") {
522
+ next[rawLayer] = enabled;
523
+ continue;
524
+ }
525
+ throw new WorldOrbitError(`Unknown layer token "${token.value}"`, line, token.column);
526
+ }
527
+ return next;
528
+ }
529
+ function parseProjectionValue(value, line, column) {
530
+ const normalized = value.toLowerCase();
531
+ if (normalized === "topdown" || normalized === "isometric") {
532
+ return normalized;
533
+ }
534
+ throw new WorldOrbitError(`Unknown projection "${value}"`, line, column);
535
+ }
536
+ function parsePresetValue(value, line, column) {
537
+ const normalized = value.toLowerCase();
538
+ if (normalized === "diagram" ||
539
+ normalized === "presentation" ||
540
+ normalized === "atlas-card" ||
541
+ normalized === "markdown") {
542
+ return normalized;
543
+ }
544
+ throw new WorldOrbitError(`Unknown render preset "${value}"`, line, column);
545
+ }
546
+ function parsePositiveNumber(value, line, column, field) {
547
+ const parsed = Number(value);
548
+ if (!Number.isFinite(parsed) || parsed <= 0) {
549
+ throw new WorldOrbitError(`Field "${field}" expects a positive number`, line, column);
550
+ }
551
+ return parsed;
552
+ }
553
+ function parseFiniteNumber(value, line, column, field) {
554
+ const parsed = Number(value);
555
+ if (!Number.isFinite(parsed)) {
556
+ throw new WorldOrbitError(`Field "${field}" expects a finite number`, line, column);
557
+ }
558
+ return parsed;
559
+ }
560
+ function createEmptyViewpointFilter() {
561
+ return {
562
+ query: null,
563
+ objectTypes: [],
564
+ tags: [],
565
+ groupIds: [],
566
+ };
567
+ }
568
+ function parseInlineFields(tokens, line) {
569
+ const fields = [];
570
+ let index = 0;
571
+ while (index < tokens.length) {
572
+ const keyToken = tokens[index];
573
+ const schema = getFieldSchema(keyToken.value);
574
+ if (!schema) {
575
+ throw new WorldOrbitError(`Unknown field "${keyToken.value}"`, line, keyToken.column);
576
+ }
577
+ index++;
578
+ const valueTokens = [];
579
+ if (schema.arity === "multiple") {
580
+ while (index < tokens.length && !isKnownFieldKey(tokens[index].value)) {
581
+ valueTokens.push(tokens[index]);
582
+ index++;
583
+ }
584
+ }
585
+ else {
586
+ const nextToken = tokens[index];
587
+ if (nextToken) {
588
+ valueTokens.push(nextToken);
589
+ index++;
590
+ }
591
+ }
592
+ if (valueTokens.length === 0) {
593
+ throw new WorldOrbitError(`Missing value for field "${keyToken.value}"`, line, keyToken.column);
594
+ }
595
+ fields.push({
596
+ type: "field",
597
+ key: keyToken.value,
598
+ values: valueTokens.map((token) => token.value),
599
+ location: { line, column: keyToken.column },
600
+ });
601
+ }
602
+ return fields;
603
+ }
604
+ function parseField(tokens, line) {
605
+ if (tokens.length < 2) {
606
+ throw new WorldOrbitError("Invalid field line", line, tokens[0]?.column ?? 1);
607
+ }
608
+ if (!getFieldSchema(tokens[0].value)) {
609
+ throw new WorldOrbitError(`Unknown field "${tokens[0].value}"`, line, tokens[0].column);
610
+ }
611
+ return {
612
+ type: "field",
613
+ key: tokens[0].value,
614
+ values: tokens.slice(1).map((token) => token.value),
615
+ location: { line, column: tokens[0].column },
616
+ };
617
+ }
618
+ function parseInfoEntry(tokens, line) {
619
+ if (tokens.length < 2) {
620
+ throw new WorldOrbitError("Invalid info entry", line, tokens[0]?.column ?? 1);
621
+ }
622
+ return {
623
+ type: "info-entry",
624
+ key: tokens[0].value,
625
+ value: tokens.slice(1).map((token) => token.value).join(" "),
626
+ location: { line, column: tokens[0].column },
627
+ };
628
+ }
629
+ function normalizeIdentifier(value) {
630
+ return value
631
+ .trim()
632
+ .toLowerCase()
633
+ .replace(/[^a-z0-9_-]+/g, "-")
634
+ .replace(/^-+|-+$/g, "");
635
+ }
636
+ function humanizeIdentifier(value) {
637
+ return value
638
+ .split(/[-_]+/)
639
+ .filter(Boolean)
640
+ .map((segment) => segment[0].toUpperCase() + segment.slice(1))
641
+ .join(" ");
642
+ }
@@ -0,0 +1,15 @@
1
+ import type { SceneRenderOptions, WorldOrbitAtlasDocument, WorldOrbitAtlasSystem, WorldOrbitDiagnostic, WorldOrbitDocument, WorldOrbitObject } from "./types.js";
2
+ interface UpgradeOptions extends Pick<SceneRenderOptions, "preset" | "projection"> {
3
+ }
4
+ export declare function upgradeDocumentToV2(document: WorldOrbitDocument, options?: UpgradeOptions): WorldOrbitAtlasDocument;
5
+ export declare function upgradeDocumentToDraftV2(document: WorldOrbitDocument, options?: UpgradeOptions): {
6
+ version: "2.0-draft";
7
+ format: "worldorbit";
8
+ sourceVersion: import("./types.js").WorldOrbitDocumentVersion;
9
+ system: WorldOrbitAtlasSystem | null;
10
+ objects: WorldOrbitObject[];
11
+ diagnostics: WorldOrbitDiagnostic[];
12
+ };
13
+ export declare function materializeAtlasDocument(document: WorldOrbitAtlasDocument): WorldOrbitDocument;
14
+ export declare function materializeDraftDocument(document: WorldOrbitAtlasDocument): WorldOrbitDocument;
15
+ export {};