Add project name validation and default value in document migration

This commit is contained in:
2026-04-11 13:25:22 +02:00
parent 88047649f9
commit b3ff49d38c
2 changed files with 44 additions and 7 deletions

View File

@@ -74,6 +74,7 @@ import {
import {
BOX_BRUSH_SCENE_DOCUMENT_VERSION,
ANIMATION_PLAYBACK_SCENE_DOCUMENT_VERSION,
DEFAULT_PROJECT_NAME,
DEFAULT_PROJECT_SCENE_ID,
ENTITY_NAMES_SCENE_DOCUMENT_VERSION,
ENTITY_SYSTEM_FOUNDATION_SCENE_DOCUMENT_VERSION,
@@ -91,6 +92,7 @@ import {
RUNNER_V1_SCENE_DOCUMENT_VERSION,
SCENE_TRANSITION_ENTITIES_SCENE_DOCUMENT_VERSION,
SPATIAL_AUDIO_SCENE_DOCUMENT_VERSION,
PROJECT_NAME_SCENE_DOCUMENT_VERSION,
SCENE_DOCUMENT_VERSION,
TRIGGER_ACTION_TARGET_FOUNDATION_SCENE_DOCUMENT_VERSION,
RUNNER_LOADING_SCREEN_SCENE_DOCUMENT_VERSION,
@@ -2548,23 +2550,44 @@ function readProjectScene(
};
}
function isProjectDocumentVersion(value: unknown): value is number {
return (
typeof value === "number" &&
Number.isInteger(value) &&
value >= MULTI_SCENE_FOUNDATION_SCENE_DOCUMENT_VERSION &&
value <= SCENE_DOCUMENT_VERSION
);
}
function readProjectName(
value: unknown,
label: string,
options: { allowMissing: boolean }
): string {
if (value === undefined && options.allowMissing) {
return DEFAULT_PROJECT_NAME;
}
return expectString(value, label);
}
export function migrateProjectDocument(source: unknown): ProjectDocument {
if (!isRecord(source)) {
throw new Error("Project document must be a JSON object.");
}
if (
(source.version === MULTI_SCENE_FOUNDATION_SCENE_DOCUMENT_VERSION ||
source.version === RUNNER_LOADING_SCREEN_SCENE_DOCUMENT_VERSION ||
source.version === SCENE_TRANSITION_ENTITIES_SCENE_DOCUMENT_VERSION ||
source.version === PLAYER_START_NAVIGATION_MODE_SCENE_DOCUMENT_VERSION) &&
isRecord(source.scenes)
) {
if (isProjectDocumentVersion(source.version)) {
if (!isRecord(source.scenes)) {
throw new Error("scenes must be an object.");
}
const materials = readMaterialRegistry(source.materials, "materials");
const assets = readAssets(source.assets);
const scenes: Record<string, ProjectScene> = {};
const allowMissingLoadingScreen =
source.version === MULTI_SCENE_FOUNDATION_SCENE_DOCUMENT_VERSION;
const allowMissingProjectName =
source.version < PROJECT_NAME_SCENE_DOCUMENT_VERSION;
for (const [sceneKey, sceneValue] of Object.entries(source.scenes)) {
scenes[sceneKey] = readProjectScene(
@@ -2580,6 +2603,9 @@ export function migrateProjectDocument(source: unknown): ProjectDocument {
return {
version: SCENE_DOCUMENT_VERSION,
name: readProjectName(source.name, "name", {
allowMissing: allowMissingProjectName
}),
activeSceneId: expectString(source.activeSceneId, "activeSceneId"),
scenes,
materials,

View File

@@ -2518,6 +2518,17 @@ export function validateProjectDocument(
): SceneDocumentValidationResult {
const diagnostics: SceneDiagnostic[] = [];
if (document.name.trim().length === 0) {
diagnostics.push(
createDiagnostic(
"error",
"invalid-project-name",
"Project names must be non-empty.",
"name"
)
);
}
if (Object.keys(document.scenes).length === 0) {
diagnostics.push(
createDiagnostic(